右值引用
左值
左值可以被看作一个具有名称的内存位置。
特征:
- 能被取地址运算符获取地址
- 可修改的左值可用作内建赋值和内建复合赋值运算符的左操作数
- 可用来初始化左值引用
纯右值
相当于 C++ 11 之前的右值。
将亡值
引用
引用 本质是别名,通过引用修改变量的值,传参时避免拷贝。
右值引用
右值引用的标志为 && ,只能指向右值,不能指向左值。
1 | int &&ref_a_right = 5; // ok |
左值引用与右值引用
1. 右值引用指向左值
使用 std::move
1 | int a = 5; // a是个左值 |
std::move 的功能就是强制把左值转换为右值,实现等同于一个类型转换:static_cast<T&& >(lvalue) 。
2. 左值引用、右值引用是什么值
声明的 左值引用 和 右值引用 都是 左值 。
万能引用
1 | // 使用 T&& param 的方式,传入左值引用或右值引用,可推导绑定左值或右值 |
引用折叠
一个模板函数,根据定义的形参和传入的实参的类型,我们可以有下面四中组合:
- 左值-左值 T& & # 函数定义的形参类型是左值引用,传入的实参是左值引用
- 左值-右值 T& && # 函数定义的形参类型是左值引用,传入的实参是右值引用
- 右值-左值 T&& & # 函数定义的形参类型是右值引用,传入的实参是左值引用
- 右值-右值 T&& && # 函数定义的形参类型是右值引用,传入的实参是右值引用
但是 C++中不允许对引用再进行引用,对于上述情况的处理有如下的规则:
所有的折叠引用最终都代表一个引用,要么是左值引用,要么是右值引用。规则是:如果任一引用为左值引用,则结果为左值引用。否则(即两个都是右值引用),结果为右值引用。
所以最后结果是:
- T& & = &
- T& && = &
- T&& & = &
- T&& && = &&
当且仅当函数形参为右值引用且传入参数也为右值引用时,最终折叠后为右值引用
完美转发
使用 std::forward 进行完美转发,std::forward 能够将正确的引用类型转发。
移动语义
在进行对象的复制时,可能有两种需求:一种是深拷贝,开辟新的内存空间,拷贝原对象到这个新的内存空间;另一种则是通过右值引用,将原对象的成员通过修改标记的方式重新由新对象的成员指向,然后将原对象的所有成员清空。
调用赋值运算符时,也同理。

