您的位置:首页 > 编程语言 > C语言/C++

The New C++ -- 变量 (7. 左值,右值)

2012-02-10 12:46 295 查看
左值右值也是C++中的一个很常见也很重要的概念,但奇怪的是大部分教科书并不会详细提及。本系列文章中的很多地方都会提到左值右值,请务必仔细理解。

左值(lvalue),源自于left-value,原本是指赋值号左边的值。右值(rvalue),源自于right-value,原本是指赋值号右边的值。例如,

int var;
var = 3;


在给var这个变量赋值的这个表达式中,var为左值,3为右值。我们提到过的几种基本数据类型的字面值常量全部为右值。例如你不可以

2 = 3; //错误


因为2为右值,不可放在赋值号左端。

随着C++的发展,左值和右值的意义已经不仅仅是赋值号左边和右边那么简单了。当然上面的例子还是成立的,只是左值和右值有了更复杂的解释,例如右值在C++中是可以被放在赋值号左边的,虽然这种情况很少见(以后遇到我们会指出总结)。左值在C++中指的是有地址的内存对象。内存对象即为内存中的一段存储空间,有地址即意味着该存储空间确确实实存在于内存之中。因为被定义的变量都为有地址的内存对象,所以变量一旦被定义,即为左值。有两种特例除外,第一,临时对象是右值,我们待会儿会讲到。第二,无名字的右值引用(关于引用和右值引用我们很快就会讲到)虽然存在于内存之中,但是C++规定其为一个右值。

右值在现代C++中指的是非内存对象,临时对象,或者无名字的右值引用。基本类型的字面值常量例如3L,3.14,'x'等都不是内存对象,因为编译器一般并不在内存中为这些字面值常量预留空间,所以他们都为右值。注意的是,字符串字面值常量是一个左值,因为字符串字面值常量是存在于内存空间之中的,实际上字符串字面值常量是一个数组类型(见下节),除字符串字面值常量的其他字面值常量统统为右值。

临时对象是解析表达式的过程中产生的临时值,例如,

int var1 = 3;
int var2 = 4;
int var3 = var1 * 3 + var2;


其中var1,var2和var3都为左值,但是var1*3的运行结果和var1*3+var2的运行结果是临时对象,都为右值。

有些机警的读者一定想到了下面这种情况,

int var1 = 3;
int var2 = var1;


如果我们说var1和var2都为左值,为何var1可以放在赋值号右边呢?这牵扯到C++的隐性类型转换。在C++中,所有的左值都可以隐性转换到右值,被称为左值到右值的转换(lvalue to rvalue conversion)。C++的每一个操作符(operator)都规定了他的操作数(operand)是左值或者右值。例如地址操作符& 要求操作数必须为左值。

int var = 3;
std::cout << std::hex << &var << " " << &3 << std::endl;


& 要求操作数必须为左值。在上例中,var是左值,所以&var是正确的用法。但因为3是右值,所以&3是错误的用法。有一种流行的区分左值和右值的方法是,凡是能够放在&后面取其地址的,都为左值,凡是不能放在&后面取其地址的,都为右值。但我认为这种说法有点因果颠倒。并不是因为能够放在&后面才是左值,而是因为是左值,所以才能够被放在&后面。

注意因为字符串字面值常量是左值,意味着他是一个存在于内存空间的一段内存对象,我们可以取其首地址。有兴趣的读者可以自己试验。

赋值号操作符要求左面为左值,右面为右值(注脚:注意这个规则对用户自定义类型来说有不符合规则的特例)。其他所有操作符例如加法操作符,减法操作符等对操作数的要求都将在操作符一章中详述。

C++规定,当操作符要求操作数为右值,但是提供的操作时却是左值的时候,就会自动执行左值到右值的转换。所以上例中例如var1=var2是成立的,因为var2被自动转换为右值。左值和右值在这些简单的例子中并无太大用处,因为你并不需要左值和右值的概念来理解赋值号和地址操作符。但他们在其他的一些情况,特别是涉及到左值引用和右值引用的时候会十分有用处,我们稍后再谈。

小知识:C++的最新标准详细的地解释了左值和右值的概念,也更细化的将所有表达式分为左值(lvalue),失效值(xvalue,源自expiring value)和纯右值(prvalue,源自pure rvalue)。其中左值和失效值合称为泛左值(glvalue,源自generalized lvalue),失效值和纯右值合称为右值(rvalue)。本系列教程并不采用如此的细分,因为这只会造成读者困惑。简单的说,左值和我们说的一样,是一个存在于内存中的对象,除临时对象和无名字的右值引用。失效值仅有一种情况:无名字的右值引用。纯右值包括非内存对象和临时对象。失效值和纯右值合称右值,和我们定义的一样。失效值和左值和称为泛左值。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: