简单定义
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++中接受常量引用作为函数形参成为可能,这避免了一些不必要的临时对象的拷贝和构造。