2020-10-16

左值与右值
①左值:能对表达式取地址、或具名对象/变量。一般指表达式结束后依然存在的持久对象。
②右值:不能对表达式取地址,或匿名对象。一般指表达式结束就不再存在的临时对象。

左值引用与右值引用
基本概念
我们平时经常使用的引用就是左值引用,通过 & 获取左值引用。为了支持移动操作,新标准引入 右值引用 (rvalue reference)。顾名思义,右值引用就是将引用绑定到右值。可以通过 && 来获取右值引用。比如:

int i = 42;
int &&r = i * 2; // 将 i * 2 的结果绑定到 r 上
要注意只能将右值绑定到右值引用上,并且左值引用不能绑定右值,以下几种用法都是错误的:

int i = 42;
int &&rr = i; // 错误,i 是左值
int &r = i * 2; // 错误,i * 2 是右值
但是右值可以绑定到 const 的左值引用上:

int i = 42;
const int &r = i * 42; // 正确,可以将 const 引用绑定到右值上
可能一开始会觉得 const 引用可以绑定右值很奇怪,引用并不是对象,他只是为已经存在的对象另取一个名字而已,所以像 int &r = 42 这样的语法是不允许的,因为 42 不是一个对象,只是一个普通字面数值而已,而 const 引用却是一个例外,如果我们将这个过程拆开来看,就可以知道为什么有这个例外了:

// 我们可以先看看常量引用被绑定到另外一种类型上时到底发生了什么
double dval = 3.14;
const int &ri = dval;
// 以上将一个双精度浮点数绑定到整型引用上,所以编译器会对其进行类型转换:
const int tmp = dval; // 先将双精度浮点数变成一个整型常量
const int &ri = tmp; // 让常量引用 ri 绑定到这个临时变量上
这种情况下,ri 会被绑定到一个 临时量 (temporary)对象上,所谓临时量就是当编译器需要一个空间来暂存表达式的求值结果时临时创建的一个未命名的对象。 创建临时量是需要消耗资源的,这也是本文的主题之一:右值引用的由来。

我们再来看看如果 ri 不是常量引用会发生什么:

double dval = 3.14;
int &ri = dval;
// 以上将一个双精度浮点数绑定到整型引用上,所以编译器会对其进行类型转换:
const int tmp = dval; // 还是先将双精度浮点数变成一个整型常量
int &ri = tmp; // 再让这个普通引用和 tmp 绑定
可以看到,这样的情况下,我们可以对 ri 进行赋值,因为 ri 并不是常量引用。但有两个问题:

tmp 是常量,而我们却用一个不是常量的引用与其绑定,这是不被允许的。
就算我们可以对其进行绑定,而我们绑定的是 tmp,而不是 dval,所以我们对 ri 赋值并不会改变 dval 的值。
于是乎,编译器直接禁止了这种行为。而常引用就不一样了,反正我们也不会改变其值,只是需要知道它的值而已,并且也不违反语法规则,所以将常引用与这种临时量绑定的行为是被允许的。

通过上例我们又可以推出一个规则:引用类型必须与其所引用的对象类型保持一致,不然就会引发临时量的产生,从而引发以上两个问题。同样,常引用除外。

同理我们推出原问题的解:一个字面值如 42,也会产生一个临时量,若不是常引用,同样会引发上文提到的两个问题,所以,我们只可以用常引用绑定右值,而普通引用是不可以的。

什么情况下使用右值引用
要了解什么情况下使用右值引用,我们就要先了充分了解右值的特性。首先与左值不同,右值是非常短暂的,它要么是字面常量,要么是在表达式求值过程中创建的临时对象。由于这样的特性我们可以总结:

所引用的对象将要被销毁
该对象没有其他用户
这就意味着,使用右值引用的代码可以自由的接管被引用对象的资源。

需要注意的是,所有的变量都是左值,我们不能将一个右值引用绑定到一个右值引用类型的变量上。比如:

int &&rr1 = 42; // 正确:字面量是右值
int &&rr2 = rr1; // 错误:rr1 是变量,虽然他是右值引用,但任然是左值
可以这样理解:变量 rr1 是持久的,它不会像字面值 42 那样转瞬即逝,所以它是左值。这就引出了下面

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值