简单定义

lvalue(locator value)代表一个在内存中占有确定位置的对象(换句话说就是有一个地址)。

rvalue  rvalue是不在内存中占有确定位置的表达式。

左值:有址值

右值:无址值

基本例子


int var; var = 4;

赋值运算符要求一个lvalue作为它的左操作数,var是一个左值,因为它是一个占确定内存空间的对象。另外下面的代码是无效的:

4 = var;        //ERROR! (var + 10) = 4; //ERROR!

常量​​4​​​和表达式​​var+1​​都不是lvalue(它们是rvalue)。因为都是表达式的临时结果,没有确定的内存空间(它们只是计算的周期驻留在临时的寄存器中)。因此给它们赋值没有语意-这里没有地方给它们赋值。


int foo() { return 2; }

int main()
{
foo() = 2;
return 0;
}

 ​​foo​​返回一个临时的rvalue。尝试给它赋值,​​foo()=2​​,是一个错误;编译器期待在赋值运算符的左部分看到一个lvalue。

不是所有的对函数调用结果赋值都是无效的。比如,C++的引用(reference)让这成为可能:

int globalvar = 20;

int& foo()
{
return globalvar;
}

int main()
{
foo() = 10;
return 0;
}

这里​​foo​​​返回一个引用,这是一个左值,所以它可以被赋值。C++从函数中返回左值的能力对于实现一些重载运算符时很重要的。一个普遍的例子是在类中为实现某种查找访问而重载中括号运算符 []。​​std::map​​可以这样做。

std::map<int, float> mymap;
mymap[10]=5.6;

给 mymap[10] 赋值是合法的因为非const的重载运算符 std::map::operator[] 返回一个可以被赋值的引用。


‘&’ 符号在C++中扮演了另一个重要角色-它允许定义 引用类型。这被称为“左值引用”。非const左值引用不能被赋右值,因为这将要求一个无效的右值到左值的转换:

std::string& sref = std::string(); //错误:无效的初始化,用一个右值类型‘std::string’初始化非const引用类型‘std::string&’
  • 常量左值引用可以被赋右值。因为它们是常量,不能通过引用被修改,因此修改一个右值没问题。这使得C++中接受常量引用作为函数形参成为可能,这避免了一些不必要的临时对象的拷贝和构造。