理解lvalues和rvalues在c/c++
在看 Eli Bendersky的文章的时候,记录一下。
引言
左值和右值在编程中不是常遇见,但出现时候,不能很快理解,所以这次做一个总结。
int foo()
{ return 2; }
int main()
{
foo()=2;
return 0;
}
gcc编译这段代码
cpp error: lvalue required as left operand of assignment
foo()=2; 左值需要一个左运算符
再用g++编译
int& foo(){ return 2;}
错误,右值错误。
定义
1,定义一个左值:表示在存储器中占用一些可识别的内存空间的对象。
2,右值用排除法来定义,每个表达式都是左值,否则是右值。所以知道rvalue是一个表达式,不表示对象,不再内存占可标识的位置空间
例子
int var;
var=4;
一个赋值操作,期望一个左值是左操作数,var就是一个左值(在存储器中占可标识的空间)。
下面这个就是错误的:
4=var; //wrong
(var+1)=4 ; //wrong
因为,对于4和(var+1),他们都不是左值(不在存储器中占可标识的空间),那么他们就成了右值(在计算期间仅驻留某个临时存储器中)都是表达式的临时结果,没有可识别的存储位置。
现在知道了第一段代码为什么错误了,因为foo函数返回了一个临时值,一个右值,foo()=2在编译器期望他应该是一个左值,能够被2赋值!
但是,并不是对所有的函数返回值调用分配都是无效的,c++的引用使得有可能
如:int globalvar=20; int &foo(){ return globalvar; } int main() {foo()=10 ; return 0}
注意:此处foo返回一个引用,他是一个lvalue。
对于c++返回左值的能力多用于重载某些运算符。常见用例是在重载方括号运算符 “[ ]” 时,如:
std::map<int, float> mymap;
mymap[10]=5.5;
在这里将5.5赋值给mymap[10]起作用是因为std::operator [] 的非常量的重载返回引用。
可修改的左值
c定义的时候,是:适用于赋值左侧的值。但是在引入const关键字后,由const定义的左值变得不可修改了。
const int a=10;
a=4; //无法分配修改了
左值和右值之间的转换
一般,对对象的值进行操作的语言在构造时候都需要使用右值(不再存储器中占可标识空间的值,将亡值)作为参数。如“+”将两个右值作为参数,返回一个右值最后赋值给左值。
int a=1;
int b=2; //a,b是左值
int c=a+b; //+需要右值,所以将ab转换成右值,并返回右值
上述进行了隐式的转换,左值——》右值
反过来呢?、将右值转换为左值。但是必须要显示地分配。绝对不可能隐式的转换右值变为左值。
使用“ * ”解引用运算符可以产生左值,将右值作为参数
int arr[]={ 1,2};
int * p= &arr[0]; //&将左值变成右值
* (p+1)=10; //正确,P+1是一个右值,但是*(p+1)是一个左值。
显式转换。
注意:“ &” 运算符取地址,采用的是左值作为参数!!!所以参数不能输入右值
如:
int var=10;
int * bad_addr=&(var+1); //这是明显错误的,因为&参数只能是左值,才能转换为右值。
正确做法:
int *p=&var;
错误:
&var=38; //&var 是一个右值!
这只是左值右值的冰山一角,还有很多值得去学习的。
还没有评论,来说两句吧...