07 - 左值,右值

左值和右值

左右值的相关概念来源于C语言,C++任何一个对象要么是左值,要么就是右值

左值:拥有地址属性的对象。它既能放在=左边的就是左值,也能放在=右边:

int i = 10;	// i为左值
int i2 = i;	// i为左值

右值:不是左值的对象。或者说无法操作地址的对象。一般来说,判断一个对象是不是右值,只需看它是不是左值,有没有地址属性,不是的话就是右值。并且 右值不可能在=左边

int i = 10;
int i2 = i + 1;	// i+1 是临时对象(有地址,但无法使用),是右值

接下来举个例子:

// i++ 与 ++i
++i = 200;	// ++i是左值
i++ = 200;	// i++是右值,错误

++i,先让i自增1,然后返回i(地址所存的值),是可操作的,因而是左值;i++,创建一个临时对象,值和i相同,然后再加1,临时对象的地址无法操作,是右值。

引用的分类

普通左值引用

就是一个对象的别名,只能绑定左值,而无法绑定常量对象:

// 普通左值引用
int i = 100;
int& refI = i;	

// 无法绑定常量对象
const int i = 100;
int& refI = i;	// 错误,如果通过的话,const形同虚设

const左值引用

可以对常量起别名,可以绑定左值和右值:

// 绑定常量对象/左值
const int i = 10;
const int& refI = i;

// 绑定右值
const int refI = (i + 1);

// 绑定常量
const int& refI = 100;

右值引用

只能绑定右值的引用:

int i = 100;
int&& rrefI = 200;	// 正确,200是右值
int&& rrefI = i + 1;// 正确。i+1是右值
int&& rrefI = i;	// 错误,i是左值

move函数

  1. 右值看重对象的值而不考虑地址,std::move()函数可以对一个左值使用,使操作系统不再在意其地址属性,将其完全视作一个右值。
  2. std::move()函数让操作的对象失去了地址属性,有义务保证 以后不再使用该变量的地址属性,即不再使用该变量,因为左值对象的地址是其使用时无法绕过的属性。
int i = 100;
int&& refI = i;				// 错误
int&& refI = std::move(i);	// 正确

临时对象

右值都是不体现地址属性的对象,右值引用主要负责处理的就是临时对象,因为它没有地址属性。

程序执行时生成的中间对象就是临时对象,临时对象都是右值对象,因为它产生后很快就可能被销毁,使用的是它的值属性。

int getI()
{
    return 10;
}

int main()
{
    int&& refI = getI();	// 函数的返回值就是一个临时对象
}

万能引用

待补充,要模板基础

参考资料

  • 飘零的落花 - 现代C++详解
  • C++20高级编程