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函数
- 右值看重对象的值而不考虑地址,
std::move()
函数可以对一个左值使用,使操作系统不再在意其地址属性,将其完全视作一个右值。 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高级编程