响应式酒店网站模板,预约代码 wordpress,广西百度推广公司,活动软文模板一.什么是左值引用 右值引用
1.左值引用 左值是一个表示数据的表达式(如变量名或解引用的指针)#xff0c;我们可以获取它的地址可以对它赋值。定义时const修饰符后的左值#xff0c;不能给他赋值#xff0c;但是可以取它的地址。左值引用就是给左值的引用#xff0c;给左…一.什么是左值引用 右值引用
1.左值引用 左值是一个表示数据的表达式(如变量名或解引用的指针)我们可以获取它的地址可以对它赋值。定义时const修饰符后的左值不能给他赋值但是可以取它的地址。左值引用就是给左值的引用给左值取别名。 int main()
{
// 以下的p、b、c、*p都是左值
int* p new int(0);
int b 1;
const int c 2;
// 以下几个是对上面左值的左值引用
int* rp p;
int rb b;
const int rc c;
int pvalue *p;
return 0;
}
2.右值引用 右值也是一个表示数据的表达式如字面常量、表达式返回值函数返回值(这个不能是左值引用返回)等等右值可以出现在赋值符号的右边但是不能出现出现在赋值符号的左边右值不能取地址。右值引用就是对右值的引用给右值取别名。 int main()
{
double x 1.1, y 2.2;
// 以下几个都是常见的右值
10;
x y;
fmin(x, y);
// 以下几个都是对右值的右值引用
int rr1 10; //常量
double rr2 x y; //临时变量
double rr3 fmin(x, y); //临时变量
// 这里编译会报错error C2106: “”: 左操作数必须为左值
10 1;
x y 1;
fmin(x, y) 1;
return 0;
} 区分左值右值关键就看能否取地址左值可以取地址右值不能取地址。 注意 int rr110 10是常量是右值那rr1是右值吗 rr1是左值因为rr1要有空间存储10所以有地址。可以对它本身进行修改但有const 修饰的const int rr1不能。 左值/右值引用引用的一定是左值/右值吗
1.左值 1. 左值引用只能引用左值不能引用右值。 2. 但是const左值引用既可引用左值也可引用右值。 int main()
{// 左值引用只能引用左值不能引用右值。int a 10;int ra1 a; // ra为a的别名//int ra2 10; // 编译失败因为10是右值// const左值引用既可引用左值也可引用右值。const int ra3 10;const int ra4 a;return 0;
}
2.右值 1. 右值引用只能右值不能引用左值。 2. 但是右值引用可以move以后的左值。move原理和强转一致只是把左值属性转换成右值在底层实现时左值右值没有区别只是为了编译通过 int main()
{// 右值引用只能右值不能引用左值。int r1 10;// error C2440: “初始化”: 无法从“int”转换为“int ”// message : 无法将左值绑定到右值引用int a 10;//int r2 a;// 右值引用可以引用move以后的左值int r3 std::move(a);return 0;
}
二.左值引用使用场景 当我们进行传参函数返回值时 直接引用就可以减少拷贝提高效率。 void func1(bit::string s)
{}
void func2(const bit::string s)
{}
int main()
{bit::string s1(hello world);// func1和func2的调用我们可以看到左值引用做参数减少了拷贝提高效率的使用场景和价值func1(s1);func2(s1);// string operator(char ch) 传值返回存在深拷贝// string operator(char ch) 传左值引用没有拷贝提高了效率s1 !;return 0;
}
左值引用的短板 当函数返回值是一个局部变量出了作用域就会销毁这样返回的左值引用就没有意义了只能进行拷贝 传值返回。 string operator(const string s, char ch)
{string ret(s);ret.push_back(ch);return ret;
} ret左值出了作用域就会销毁 三.右值引用使用场景 在C11前都是在mian()函数中定义ret再传给operator()延长生命周期。 之后引出了右值引用和移动语义来解决。 1.移动语义 将一个对象的资源转到另一个对象上。 1.移动构造 移动构造和拷贝构造区别在于移动构造只能接受右值/move(左值) 。而拷贝构造左值右值const都可以接收。 当我们传右值编译器会优先匹配更符合的 移动构造。 我们知道to_string中创建的str左值但马上被销毁编译器会自动识别为右值属于将亡值。这样就可以走移动构造转移资源 减少拷贝。 2.移动赋值 用常量1234初始化会调用移动构造to_string返回值再通过移动复制将资源转移到ret1上。 // 移动赋值
string operator(string s)
{
cout string operator(string s) -- 移动语义 endl;
swap(s);
return *this;
}
int main()
{
bit::string ret1;
ret1 bit::to_string(1234);
return 0;
}
// 运行结果
// string(string s) -- 移动语义
// string operator(string s) -- 移动语义
四.完美转发
万能引用 首先我们要了解什么是万能引用。 确定类型的 表示右值引用比如int string 但函数模板中的 不表示右值引用而是万能引用模板类型必须通过推断才能确定其接收左值后会被推导为左值引用接收右值后会被推导为右值引用。 templatetypename T
void f(T t) // 万能引用
{//...
}int main()
{int a 5; // int 左值f(a); // 传参后intconst string s(hello); // const string 左值f(s); // 传参后const stringf(to_string(1234)); // 右值 传参后 stringreturn 0;
} 注意区分右值引用和万能引用下面的函数的 T 并不是万能引用因为 T 的类型在模板实例化时已经确定。 templateclass T
class A
{void func(T a){}
};
for_ward() 为什么都调用的左值引用呢 因为在传参时右值变为了左值导致调用Fun()函数时t参数的属性永远是左值。 这时候就需要forwardT()完美转发保持参数属性左值还是左值右值还是右值。