C++中,表达式的值要么是左值,要么是右值。左值右值是相对于表达式而言的。
左值和右值
首先对于左值和右值的区分并不是简单的取决于表达式是在等号的左边或者右边。我们可以根据左值持久,右值短暂来区分。也就是说,如果一个表达式结束后其值依旧存在,那么它就是一个左值,否则就是一个右值。所以一般来说右值要么是临时对象,要么就是字面值常量。
我们也可以采用是否可以取地址的方式来判断表达式的值是一个左值还是右值。因为左值是持久的,所以其一般是可以取地址的,而右值则不可以。
一般在表达式与引用的绑定的时候,我们需要遵守下述规则,非常量引用的初始值必须为非常量左值,常量引用的初始值可以为左值、右值。这是因为右值是一个临时对象,如果将右值绑定到一个非常量引用,这会导致我们可能使用一个已经销毁的对象,这是十分危险的。
尤其注意类型转换中的隐含中间引用值的问题,如下所示
类型 | 实例 |
---|---|
左值表达式 | 返回左值引用的函数、赋值、下标运算、前置递增/递减运算 |
右值表达式 | 返回右值引用的函数、算术运算、关系运算、后置递增/递减运算 |
可参考这篇文章学习
左值引用和右值引用
首先介绍左值引用和右值引用的定义。注意:并不是左值引用就必须绑定左值(常量左值引用可以绑定右值)
左值引用:也就是常规引用。不能将其绑定到要求转换的表达式、字面值常量或者返回右值的表达式。
右值引用:必须要绑定到右值得引用。只能绑定到一个即将要销毁的对象。因此右值引用常常应用于移动对象。
int f();
vector<int> vi(100);
int &&r1 = f(); //返回会引用类型的函数返回值是右值
int &r2 = vi[0]; //下标运算取得的值是可以取地址的,是左值
int &r3 = r1; //r1是一个变量,是左值
int &&r4 = vi[0]*f(); //算数运算表达式返回右值
const int &r5 = vi[0]*f(); //const引用可以绑定到右值