“右值引用”是什么?我赌两个币,没人能讲得比我清楚!不看绝对亏!

变量、左值、右值
C/C++ 中的变量 int a = 42;
a 为具名变量,该变量为 int 类型,类型 int 是该变量的属性。42 是变量的内容(值),而且该值的类型要和该变量的类型一致。
动态类型语言如 JavaScript 中的变量 let a = 42;
a 为具名变量,但 a 没有类型属性,a 中的内容 42 具有类型 Number。
C/C++ 中 char c = a; [右值语义]
这里是将 a 的内容(值)取出来,转换成 char 的值,存到 c 中。
而 a = 123; [左值语义]
是将 123 转换成 int 的值,存到 a 中。
所以,当提到变量 a 时,就有两个语义,表示变量盒子(具有地址、类型属性)的左值语义,以及表示变量内容(所存值)的右值语义。
对以上概念的扩充。
字面量 42 是一个纯右值 prvalue,没有变量盒子的属性(不具有地址)。
void func() 函数,该函数名 func 是一个左值(具有地址)。对该函数的调用 func() 是一个 void 类型的表达式,是右值。
传统的 swap 惯用法避免复制开销
string temp;
// 对 temp 的计算与构建
// 实际返回的对象
string ret;
// 对于 STL 容器,swap 是一个开销小且有 no-except 保证的操作
ret.swap(temp);
return ret;
}
注:对于以上函数的调用 string s = create_string(),在返回阶段(按值返回)也有一次拷贝初始化,用 create_string() 中的返回值 ret 拷贝构造出调用者中的 s。根据编译优化的不同 (RVO),这个过程可能有一个中间临时对象的拷贝构造,也可能一次拷贝构造都没有,即调用者中的 s 被约束到 create_string() 中的 ret。
右值引用、移动语义 move semantic
需求和引出:上例中,在已知 temp 在 create_string() 返回后会消耗(即失效值 xvalue)情况下,如何在返回时,将 temp 内部管理的字符串资源偷取出来 (steal),放到另一个 string 对象的内部(并接受这个新对象的管理),比如调用者的 s 中,这样就避免了字符串资源拷贝。
string ret = std::move(temp);
move() 本质上是一个到 T&& 右值引用的类型转换,本例中即 ret = (string&&) temp
根据 string 构造函数 和 赋值操作 的参数,调用其 copy 版(如果参数是左值引用),或 move 版(如果参数是右值引用)
给 string 编写 move ctor/assignment 称为将 string 变为 move-aware
本例中 move 操作完成后,原先 temp 就失效了(不可用)