C++中有“左值”、“右值”的概念,C++11以后,又有了“左值”、“纯右值”、“将亡值”的概念。关于这些概念,许多资料上都有介绍,本文在拾人牙慧的基础上又加入了一些自己的一些理解,同时提出了一些需要读者特别注意的地方,主要目的有二:
1.尽可能地将这些概念介绍清楚。
2.为后续介绍完美转发和移动语义做好铺垫。
正文
一、表达式
要说清“三值”,首先要说清表达式。
定义
由运算符(operator)和运算对象(operand)①构成的计算式(类似于数学上的算术表达式)。
举例
字面值(literal)和变量(variable)是最简单的表达式,函数的返回值也被认为是表达式。
二、值类别
表达式是可求值的,对表达式求值将得到一个结果(result)。这个结果有两个属性:类型和值类别(value categories)。下面我们将详细讨论表达式的值类别②。
在c++11以后,表达式按值类别分,必然属于以下三者之一:左值(left value,lvalue),将亡值(expiring value,xvalue),纯右值(pure rvalue,pralue)。其中,左值和将亡值合称泛左值(generalized lvalue,glvalue),纯右值和将亡值合称右值(right value,rvalue)。见下图
有一点需要说明,严格来讲,“左值”是表达式的结果的一种属性,但更为普遍地,我们通常用“左值”来指代左值表达式(正如上边一段中做的那样)。所谓左值表达式,就是指求值结果的值类别为左值的表达式。通常我们无需区分“左值”指的是前者还是后者,因为它们表达的是同一个意思,不会引起歧义。在后文中,我们依然用左值指代左值表达式。对于纯右值和将亡值,亦然。
三、详细说明
事实上,无论是左值、将亡值还是纯右值,我们目前都没有一个精准的定义。它们事实上表征了表达式的属性,而这种属性的区别主要体现在使用上,如能否做运算符的左操作数、能否使用移动语义(关于移动语义,在下的后续文章中会详细介绍)等。因此,从实际应用出发,我们首先需要做到的是:给定一个表达式,能够正确地判断出它的值类别。为了使读者能够做到这一点,在下采取了一个实际的方式:先对各个值类别的特征加以描述,然后指出常见的表达式里边,哪些属于该类别。
左值
描述
能够用&取地址的表达式是左值表达式。
举例
函数名和变量名(实际上是函数指针③和具名变量,具名变量如std::cin、std::endl等)、返回左值引用的函数调用、前置自增/自减运算符连接的表达式