左值和右值
C++的表达式要不然是右值(rvalue,读作"are-value"),要不然就是左值(lvalue,读作"ell-value")。
这两个名词是从C语言继承过来的,原本是为了帮助记忆:左值可以位于赋值语句的左侧,右值则不能。
在 C++语言中,二者的区别就没那么简单了。一个左值表达式的求值结果是一个对象或者一个函数,然而以常量对象为代表的某些左值实际上不能作为赋值语句的左侧运算对象。
此外,虽然某些表达式的求值结果是对象,但它们是右值而非左值。
可以做一个简单的归纳∶
当一个对象被用作右值的时候,用的是对象的值(内容);当对象被用作左值的时候,用的是对象的身份(在内存中的位置)。
不同的运算符对运算对象的要求各不相同,有的需要左值运算对象、有的需要右值运算对象;
返回值也有差异,有的得到左值结果、有的得到右值结果。
一个重要的原则是在需要右值的地方可以用左值来代替,但是不能把右值当成左值(也就是位置)使用。
当一个左值被当成右值使用时,实际使用的是它的内容(值)。
到目前为止,已经有几种我们熟悉的运算符是要用到左值的。
- 赋值运算符需要一个(非常量)左值作为其左侧运算对象,得到的结果也仍然是一个左值。
- 取地址符作用于一个左值运算对象,返回一个指向该运算对象的指针,这个指针是一个右值。
- 内置解引用运算符、下标运算符、迭代器解引用运算符、string 和vector的下标运算符的求值结果都是左值。
- 内置类型和迭代器的递增递减运算符作用于左值运算对象,其前置版本所得的结果也是左值。
使用关键字decltype的时候,左值和右值也有所不同。
如果表达式的求值结果是左值,decltype作用于该表达式(不是变量)得到一个引用类型。
举个例子,假定p的类型是int* ,因为解引用运算符生成左值,所以decltype(*p)的结果是int&。
另一方面,因为取地址运算符生成右值,所以decltype(&p)的结果是 int**,也就是说,结果是一个指向整型指针的指针。