不管你在不在意,每个表达式都属于三种值类别(prvalue,xvalue,lvalue)中的一种。值类别可以影响表达式的含义,例如:你应该知道这个表达式是没有意义的:3 = 4,它甚至编译不过。但你可能说不出来为什么编译器会认为它编译不过。如果你使用gcc编译器,它的报错如下: error: lvalue required as left operand of assignment 这个报错中的lvalue就是数字表达式3的值类别。再者,值类别还会影响函数的重载:当某个函数有两种重载可用,其中之一接受右值引用的形参而另一个接受 const 的左值引用的形参时,右值将被绑定到右值引用的重载之上。如果你不明白这里提到的“左值引用”和“右值”是指什么的话请不要担心,这就是本文所要说明的。
从左值和右值说起
最初的时候,只有左值(lvalue)和右值(rvalue)这两个术语。它们源于C 的祖先语言:[CPL](https://en.wikipedia.org/wiki/CPL_(programming_language "CPL"))。lvalue之所以叫lvalue,是因为它常常出现在等号的左边(left-hand side of an assignment)。同样,rvalue是因为它常常出现在等号的右边(right-hand side of an assignment)。回顾一下上面的3 = 4编译报错,就是因为编译器要求等号的左边得是一个lvalue,而数字3其实是一个rvalue,所以这个是无法通过编译的。C语言遵循了相似的分类法,但是否需要等号赋值已经不再重要。在C语言中,标识一个对象的表达式称之为左值,不过lvalue已经是“locator value”的简写,因为lvalue对应了一块内存地址。你可以简单的理解为:左值对应了具有内存地址的对象,而右值仅仅是临时使用的值。例如int a = 1中,a是左值,1是右值。
C 11中的值类别
C 中对于值类别的定义也经历一些变化。从C 11标准开始,值类别早以不止是lvalue和rvalue两种这么简单。但情况也不算太坏,因为主要的值类别有:lvalue,prvalue 和 xvalue三种。加上两种混合类别:glvalue和rvalue,一共有五种。我们来看一下它们的定义:
A glvalue(generalized lvalue) is an expression whose evaluation determines the identity of an object, bit-field, or function.
A prvalue(pure rvalue) is an expression whose evaluation initializes an object or a bit-field, or computes the value of an operand of an operator, as specified by the context in which it appears, or an expression that has type cv void.
An xvalue(eXpiring value) is a glvalue that denotes an object or bit-field whose resources can be reused (usually because it is near the end of its lifetime).