欢迎光临散文网 会员登陆 & 注册

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

2023-04-27 09:21 作者:breakerzh  | 我要投稿

变量、左值、右值


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 惯用法避免复制开销


08:02

string create_string() {

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


10:00


需求和引出:上例中,在已知 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 就失效了(不可用)


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

分享到微博请遵守国家法律