理解lvalue和rvalue

Lvalues and Rvalues

An object is a region of storage that can be examined and stored into. An lvalue is an expression that refers to such an object. An lvalue does not necessarily permit modification of the object it designates. For example, a const object is an lvalue that cannot be modified. The termmodifiable lvalue is used to emphasize that the lvalue allows the designated object to be changed as well as examined. The following object types are lvalues, but not modifiable lvalues:

  • An array type
  • An incomplete type
  • const-qualified type
  • An object is a structure or union type and one of its members has a const-qualified type

Because these lvalues are not modifiable, they cannot appear on the left side of an assignment statement.

The term rvalue refers to a data value that is stored at some address in memory. An rvalue is an expression that cannot have a value assigned to it. Both a literal constant and a variable can serve as an rvalue. When an lvalue appears in a context that requires an rvalue, the lvalue is implicitly converted to an rvalue. The reverse, however, is not true: an rvalue cannot be converted to an lvalue. Rvalues always have complete types or the void type.

 ISO C defines a function designator as an expression that has function type A function designator is distinct from an object type or an lvalue. It can be the name of a function or the result of dereferencing a function pointer. The C language also differentiates between its treatment of a function pointer and an object pointer.

 On the other hand, in C++, a function call that returns a reference is an lvalue. Otherwise, a function call is an rvalue expression. In C++, every expression produces an lvalue, an rvalue, or no value.

In both C and C++, certain operators require lvalues for some of their operands. The table below lists these operators and additional constraints on their usage.

Operator Requirement
& (unary) Operand must be an lvalue.
++ -- Operand must be an lvalue. This applies to both prefix and postfix forms.
= += -= *= %= <<= >>= &= ^= |= Left operand must be an lvalue.

For example, all assignment operators evaluate their right operand and assign that value to their left operand. The left operand must be a modifiable lvalue or a reference to a modifiable object.

The address operator (&) requires an lvalue as an operand while the increment (++) and the decrement (--) operators require a modifiable lvalue as an operand. The following example shows expressions and their corresponding lvalues.

Expression Lvalue
x = 42 x
*ptr = newvalue *ptr
a++ a
int& f()  The function call to f()

  The remainder of this section is platform-specific and pertains to C only.

When compiled with the GNU C language extensions enabled, compound expressions, conditional expressions, and casts are allowed as lvalues, provided that their operands are lvalues. The use of this language extension is deprecated for C++ code.

A compound expression can be assigned if the last expression in the sequence is an lvalue. The following expressions are equivalent:

(x + 1, y) *= 42; x + 1, (y *=42);

The address operator can be applied to a compound expression, provided the last expression in the sequence is an lvalue. The following expressions are equivalent:

&(x + 1, y); x + 1, &y;

A conditional expression can be a valid lvalue if its type is not void and both of its branches for true and false are valid lvalues. Casts are valid lvalues if the operand is an lvalue. The primary restriction is that you cannot take the address of an lvalue cast.

---------------------------------------------------

今天看C++模板的资料,里面说到lvalue,rvalue的问题,这个问题以前也看到过,也查过相关资料,但是没有考虑得很深,只知道rvalue不能取地址,不能赋值等等一些规则。今天则突然有了更深层次的理解(也可以说是顿悟,耗时不过几秒钟),记录下来。

下面是我对这两个单词字面的意思的猜测:

  • lvalue估计来源于left value。 在赋值语句中lvalue = rvalue;位置处于左边。就是可以修改的值。
  • rvalue估计来源于right value。处于赋值语句右边,是只读的不可修改的值。

接下来是我所悟到内容的详细分析

  • lvalue是可以赋值的,说明它是一个变量,它在内存中一定存在,一定有地址。所以&lvalue是有效的,能取到在内存中的地址。

    访问lvalue一定会导致CPU访问存储器(相对较慢的操作)。

    lvalue的例子:

    1. int a;
    2. a = 10; // a是lvalue。
    3. int* p = &a; // &a是rvalue。
    4. &a = 0; //错误,&a不是lvalue,因为a的地址一旦分配好了,就不能改变了。

    int a; a = 10; // a是lvalue。 int* p = &a; // &a是rvalue。 &a = 0; //错误,&a不是lvalue,因为a的地址一旦分配好了,就不能改变了。

  • rvalue是不可以赋值的,它不是一个变量,在内存中没有存在,没有地址。它要么是存在于CPU的寄存器中,要么是存在于指令中(立即数)。所以只要对rvalue取地址,那么就一定是错误的(编译器会抱怨的)。

    访问rvalue不会导致CPU访问存储器(对立即数和寄存器的访问很快)。

    rvalue的例子:

    1. int a;
    2. a = 10; // 10是rvalue,它没有地址,&10就是错误的表达式。从汇编语言的角度来看,10是直接存在于MOV指令中的立即数。
    3. 10 = a; // 错误,10是rvalue,不可赋值。
    4. //函数返回值属于rvalue,因为返回值通常用CPU寄存器传递,没有地址。
    5. int foo()
    6. {
    7. return 0;
    8. }
    9. int b = foo(); //没问题,函数返回值是rvalue。
    10. int* p = &foo(); //错误,rvalue没有地址。
    11. void bar(int& i)
    12. {
    13. }
    14. bar(foo()); //错误,bar函数参数需要的是lvalue。

    int a; a = 10; // 10是rvalue,它没有地址,&10就是错误的表达式。从汇编语言的角度来看,10是直接存在于MOV指令中的立即数。 10 = a; // 错误,10是rvalue,不可赋值。 //函数返回值属于rvalue,因为返回值通常用CPU寄存器传递,没有地址。 int foo() { return 0; } int b = foo(); //没问题,函数返回值是rvalue。 int* p = &foo(); //错误,rvalue没有地址。 void bar(int& i) { } bar(foo()); //错误,bar函数参数需要的是lvalue。

  • 函数的返回值是rvalue,对于返回int, char 等这样最基本的类型,是通过CPU寄存器返回的,因此返回值没有地址是可以理解的。但是如果函数返回的是一个用户自定义类型的对象,肯定不可能通过寄存器来返回这个对象值的(寄存器大小数量都有限,对象的大小可以非常大),那究竟是怎样返回对象的呢?
    1. class UDT
    2. {
    3. int data[100];
    4. public:
    5. UDT()
    6. {
    7. printf("construct/n");
    8. }
    9. BBB& operator = (BBB& )
    10. {
    11. printf("operator =/n");
    12. return *this;
    13. }
    14. };
    15. UDT foo()
    16. {
    17. return UDT();
    18. }
    19. void main()
    20. {
    21. UDT obj = foo();
    22. }
    23. //输出:
    24. construct

    class UDT { int data[100]; public: UDT() { printf("construct/n"); } BBB& operator = (BBB& ) { printf("operator =/n"); return *this; } }; UDT foo() { return UDT(); } void main() { UDT obj = foo(); } //输出: construct

    带着疑问,我查了查vc编译出来的代码,原来obj这个局部变量的地址被压入了堆栈,foo函数内部以堆栈上的obj地址作为this指针调用了UDT的构造函数。噢,难怪执行UDT obj = foo();这个语句只有调用了一次构造函数,而没有调用operator =,这都是因为函数返回值必须是rvalue这个规则所带来的好处,如果返回值是一个lvalue,那么这个语句一定会调用operator = 运算符。

http://blog.csdn.net/rogerhe/article/details/6410993

posted on 2011-11-16 16:58 On the way 阅读(...) 评论(...) 编辑 收藏

转载于:https://www.cnblogs.com/areliang/archive/2011/11/16/2251480.html

理解lvalue和rvalue相关推荐

  1. 理解C++ lvalue与rvalue

    一个众所周知的危险错误是,函数返回了一个局部变量的指针或引用.一旦函数栈被销毁,这个指针就成为了野指针,导致未定义行为.而左值(lvalue)和右值(rvalue)的概念,本质上,是理解"程 ...

  2. C++,创建临时变量传递给参数为常量的函数,lvalue与rvalue的转换。

    在开始之前,先来看一个例子 void func(const int& a); int main() {int b=1;func(b*2); //正常运行func(2); //报错 } 首先,注 ...

  3. [C++] Lvalue and Rvalue Reference

    Lvalue and Rvalue Reference int a = 10;// a is in stack int& ra = a; // 左值引用 int* && pa ...

  4. c++的lvalue和rvalue以及引用

    目录 (0)lvalue和rvalue (1)左值引用 (2)右值引用 (3)move() (0)lvalue和rvalue 下面是我对这两个单词字面的意思的猜测: lvalue估计来源于left v ...

  5. C和C++里面的lvalue 和 rvalue的释义

        在看gcc的文档的时候,看到一个词lvalue,查了金山词霸其释义为 lvalue [计] 左值.因为的确在介绍编译原理的课程中听过这个词,大致知道其意思就没有多想.但是看完gcc文档的这个篇 ...

  6. 关于lvalue and rvalue

    2019独角兽企业重金招聘Python工程师标准>>> lvalue :An object is a region of storage that can be examined a ...

  7. c语言中字符串关于左值,关于左值lvalue和右值rvalue的一点理解

    发现很多朋友对"lvalue"和"rvalue"理解有误,我先谈谈自己对此的一些理解,并期望能够引起更多朋友的广泛讨论.也算起到抛砖引玉的作用吧.引用:注:这里 ...

  8. C++的左值(lvalue)和右值(rvalue)

    背景 lvalue(左值).rvalue(右值)这些术语来自C语言(当然,C语言的术语习惯也可能来自更早的语言,Gemfield就不追溯了).在C语言中,lvalue和rvalue中的l和r是left ...

  9. C++中rvalue和lvalue详悉

    以下内容是参考书籍以及晚上的内容,整理而成,仅供参考~~ lvalue和rvalue 在计算机的远古时代,变量的lvalue和rvalue是指: lvalue:变量在内存中的位置.通过它能够找到内存中 ...

最新文章

  1. 数据同步的终极解决方案,阿里巴巴开源的Canal框架当之无愧!!
  2. linux memcache 源码包,Linux 安装Memcache扩展支持(示例代码)
  3. 服务器控件的异步请求——UpdatePanel和ScriptManager
  4. 1.2 内置异常类,异常方法
  5. 全球及中国智能照明行业应用状况及竞争格局展望报告2021-2027年
  6. boost::contract模块实现courier信使的测试程序
  7. C++ primer 第15章 面向对象程序设计
  8. python写文件格式转换程序_python实现txt文件格式转换为arff格式
  9. ado.net 操作mysql_ADO.NET操作数据库(一)
  10. asp fso的神奇功能
  11. 谁爱谁都没有错... ...
  12. ATmega128A 串口问题
  13. 黑科技VNET——最好用的Android抓包神器
  14. Sqoop基于时间列的增量数据之LastModified方式
  15. proxy代理配置及解析
  16. 病来如山倒,病去如抽丝
  17. javac.exe 、 java.exe、 javaw.exe 、 javaws.exe有什么区别?
  18. 选择SaaS供应商的15个关键问题
  19. htc 8x android,颠覆之作的探究,HTC 8X拆解多图欣赏
  20. 【go get】下载的包放在哪里了?

热门文章

  1. 用python函数画德国国旗代码_用Python绘制一面国旗
  2. Hive优化总结(史上最全)
  3. Git彻底删除历史记录中大文件
  4. 如何用万用表测量device管脚和电源的开短路
  5. 计算机会计专用符号,代表会计的符号
  6. cocos 链接PHP服务器,Cocos网络篇[3.2](2) ——HTTP连接
  7. SDUT 2138 图结构练习——BFSDFS——判断可达性
  8. 基于以太坊dpos实现
  9. 用友ERP-U8为奥运供应商信息化加油---万象汽车ERp
  10. java sql 递归查询,My SQL 中如何递归查询所有的父节点