转载:C++中的左值和右值 | 转载:C++中的右值引用和移动
一、左值(lvalue):
简单的来说,能取地址的变量一定是左值,有名字的变量也一定是左值,最经典的void fun(p&& shit),其中shit也是左值,因为右值引用是左值(所以才会有move,forward这些函数的产生,其中move出来一定是右值,forward保持变量形式和之前的不变,就是为了解决右值引用是左值的问题)。至于为什么不能把等号左边看成左值,因为在C++中,等号是可以运算符重载的,等号完全可以重载成为等号左边为右值的形式。
左值是可以取地址的,这也是区分左值和右值的唯一正确的标志
注意:字符串是左值,字面值常量是右值。例如:"Hello World!"
是左值,666,9.9,true,false,nullptr
都是纯右值
二、右值(rvalue):
当函数返回一个值时编译器会创建一个零时且完整的对象,这个对象就是一个右值
- prvalue(纯右值):
纯右值是传统右值的一部分,纯右值是表达式产生的中间值,不能取地址
- rvalue(右值):
和左值不同,右值不可以取地址,右值不能在内建等号的左边,如果运算符重载右值是可以在等号左边的
三、消亡值(xvalue):
本质上,消亡值就是通过右值引用产生的值。右值一定会在表达式结束后被销毁,比如return x(x被copy以后会被销毁), 1+2(3这个中间值会被销毁)。
四、右值引用
右值引用用&&
表示,字面意思就是以引用传递(而非值传递)的方式使用右值
和声明左值引用一样,右值引用也必须立即进行初始化操作,且只能使用右值进行初始化,例如:
int num = 10;
//int && a = num; //错误,右值引用不能初始化为左值
int && a = 10;
五、引用和std::ref以及std::cref
转载:std::move、std::ref和std::bind
std::ref只是尝试模拟引用传递,并不能真正变成引用,在非模板情况下,std::ref根本没法实现引用传递,只有模板自动推导类型时,ref能用包装类型reference_wrapper来代替原本会被识别的值类型,而reference_wrapper能隐式转换为被引用的值的引用类型。std::ref主要是考虑函数式编程(如std::bind)在使用时,是对参数直接拷贝,而不是引用。比如thread的方法传递引用的时候,必须外层用ref来进行引用传递,否则就是浅拷贝。
std::ref用于包装按引用传递的值。std::cref用于包装按const引用传递的值
六、std::reference_wrapper
七、常引用、引用、传引用、传值
引用本质只是另一个对象的别名。对引用别名的操作即是对本身变量的操作。
常引用只能指向一个常量对象,不能指向另一个常量对象。