梁越

c++左值右值解释

0 人看过

现在网上对于左值右值的解释很多废话

什么是左值和右值

左值就是有指向特定内存地址的变量,反之就是右值;

而且左值一般出现在等号左边,右值一般出现在等号右边

最简单的

int x = 666;   // ok

上面的x是左值,666是右值;因为x是一个变量,运行的时候给x分配了内存,x是有地址的,一个有地址的变量就是左值,而666是一个常量,是一个右值。

然后对于左值,不一定都放在等号左边,例如:

int *y=&x;   //ok

我们看上面,x作为一个左值出现在了右边,y是一个指针变量,存放地址,而x也是一个变量,但是使用取地址符&之后得到的是x的地址,地址是一个常量,也就是说&x是一个右值,所以上式成立

所以上面两个都是正确使用左值右值的例子,下面这个则是错误的例子

int y;
666 = y; // error!

原因不难看出666是个右值,y是左值,以上代码在gcc运行时会出现如下错误提示:

error: lvalue required as left operand of assignment

下面这个操作也是错的

int *y=&666; //error

对一个常量取地址是不存在的,取地址符只能对一个左值操作

这个在gcc中的错误提示:

error: lvalue required as unary ‘&’ operand`

&地址符需要一个左值

方法返回左值和右值

等号左边一般是左值,所以下面这个操作是错误的:

int setValue()
{
    return 6;
}

setValue() = 3; // error

返回的6是个右值,不能作为左值使用

但是如果改为以下写法,那就是正确的:

int global = 100;

int& setGlobal()
{
    return global;    
}

setGlobal() = 400; // OK

这里的setGlobal返回的是一个引用,引用是指向一个有效地址的,属于左值,所以以上操作合理,注意区分取地址符和引用

左值到右值的转换

有时候我们会看见左值也出现在等号右边,除了取地址符外,还有以下情况:

int x = 1;
int y = 3;
int z = x + y;   // ok

这里x和y作为左值居然在等号右边,但是也合理,是因为这里做了一个隐式转换。还有很多的其他运算会进行隐式转换,如减法、乘法、除法。

左值引用

常见的引用使用方式如下:

int y = 10;
int& yref = y;
yref++;        // y is now 11

这里的y和yref都是左值,为什么可以这样呢,这是因为c++编译器规定非常量引用的变量初始值必须为左值,所以下面的操作是错误的:

int& yref = 10;

10是右值,不能用来初始化引用,但是如果是常量引用的话,就合理了

const int& yref=10;

如果忽略这个知识点,很容易在给函数参数赋值的时候出现错误

void fnc(int& x)
{
}

int main()
{
    fnc(10);  // Nope!
    // This works instead:
    // int x = 10;
    // fnc(x);
}
void fnc(const int& x)
{
}

int main()
{
    fnc(10);  // OK!
}

而对于常量引用的底层实际上隐式定义了一个临时的变量

const int& ref = 10;

//相当于
int __internal_unique_name = 10;
const int& ref = __internal_unique_name;