左值引用指向左值
右值引用指向右值
int a = 5;
int &ref_a = a; // 左值引用指向左值,编译通过
int &ref_a = 5; // 左值引用指向了右值,会编译失败
int &&ref_a_right = 5; // ok
int a = 5;
int &&ref_a_left = a; // 编译不过,右值引用不可以指向左值
ref_a_right = 6; // 右值引用的用途:可以修改右值
引用是变量的别名,由于右值没有地址,没法被修改,所以左值引用无法指向右值。
右值引用专门为右值而生,可以指向右值,不能指向左值
左值引用指向右值(特殊)
但是,const左值引用是可以指向右值的:
const int &ref_a = 5; // 编译通过
const左值引用不会修改指向值,因此可以指向右值,这也是为什么要使用const &作为函数参数的原因之一,
如std::vector的push_back:
void push_back (const value_type& val);
如果没有const,vec.push_back(5)这样的代码就无法编译通过了。
右值引用指向左值(特殊)
有办法,std::move:
int a = 5; // a是个左值
int &ref_a_left = a; // 左值引用指向左值
int &&ref_a_right = std::move(a); // 通过std::move将左值转化为右值,可以被右值引用指向
cout << a; // 打印结果:5
在上边的代码里,看上去是左值a通过std::move移动到了右值ref_a_right中,那是不是a里边就没有值了?并不是,打印出a的值仍然是5。
std::move是一个非常有迷惑性的函数,不理解左右值概念的人们往往以为它能把一个变量里的内容移动到另一个变量,
但事实上std::move移动不了什么,唯一的功能是把左值强制转化为右值,
让右值引用可以指向左值。其实现等同于一个类型转换:static_cast<T&&>(lvalue)。
所以,单纯的std::move(xxx)不会有性能提升,std::move的使用场景在第三章会讲。
左值引用、右值引用本身是左值
被声明出来的左、右值引用都是左值。 因为被声明出的左右值引用是有地址的,也位于等号左边。
仔细看下边代码:
// 形参是个右值引用
void change(int&& right_value) {
right_value = 8;
}
int main() {
int a = 5; // a是个左值
int &ref_a_left = a; // ref_a_left是个左值引用
int &&ref_a_right = std::move(a); // ref_a_right是个右值引用
change(a); // 编译不过,a是左值,change参数要求右值
change(ref_a_left); // 编译不过,左值引用ref_a_left本身也是个左值
change(ref_a_right); // 编译不过,右值引用ref_a_right本身也是个左值
change(std::move(a)); // 编译通过
change(std::move(ref_a_right)); // 编译通过
change(std::move(ref_a_left)); // 编译通过
change(5); // 当然可以直接接右值,编译通过
cout << &a << ' ';
cout << &ref_a_left << ' ';
cout << &ref_a_right;
// 打印这三个左值的地址,都是一样的
}
看完后你可能有个问题,std::move会返回一个右值引用int &&,它是左值还是右值呢?
或者说:作为函数返回值的 && 是右值(函数返回对象在右边),直接声明出来的 && 是左值。
** 这同样也符合第一章对左值,右值的判定方式:其实引用和普通变量是一样的,int &&ref = std::move(a)和 int a = 5没有什么区别,等号左边就是左值,右边就是右值。**
最后,从上述分析中我们得到如下结论:
从性能上讲,左右值引用没有区别,传参使用左右值引用都可以避免拷贝。
右值引用可以直接指向右值,也可以通过std::move指向左值;
而左值引用只能指向左值(const左值引用也能指向右值)。
作为函数形参时,右值引用更灵活。
虽然const左值引用也可以做到左右值都接受,但它无法修改,有一定局限性。
void f(const int& n) {
n += 1; // 编译失败,const左值引用不能修改指向变量
}
void f2(int && n) {
n += 1; // ok
}
int main() {
f(5);
f2(5);
}
标签:std,右值,int,左值,引用,ref
From: https://www.cnblogs.com/niumachen/p/18429260