理解lvalue和rvalue
今天看C++模板的资料,里面说到lvalue,rvalue的问题,这个问题以前也看到过,也查过相关资料,但是没有考虑得很深,只知道rvalue不能取地址,不能赋值等等一些规则。今天则突然有了更深层次的理解(也可以说是顿悟,耗时不过几秒钟),记录下来。
下面是我对这两个单词字面的意思的猜测:
- lvalue估计来源于left value。 在赋值语句中lvalue = rvalue;位置处于左边。就是可以修改的值。
- rvalue估计来源于right value。处于赋值语句右边,是只读的不可修改的值。
接下来是我所悟到内容的详细分析
- lvalue是可以赋值的,说明它是一个变量,它在内存中一定存在,一定有地址。所以&lvalue是有效的,能取到在内存中的地址。
访问lvalue一定会导致CPU访问存储器(相对较慢的操作)。
lvalue的例子:
- int a;
- a = 10; // a是lvalue。
- int* p = &a; // &a是rvalue。
- &a = 0; //错误,&a不是lvalue,因为a的地址一旦分配好了,就不能改变了。
rvalue是不可以赋值的,它不是一个变量,在内存中没有存在,没有地址。它要么是存在于CPU的寄存器中,要么是存在于指令中(立即数)。所以只要对rvalue取地址,那么就一定是错误的(编译器会抱怨的)。
访问rvalue不会导致CPU访问存储器(对立即数和寄存器的访问很快)。
rvalue的例子:
- 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寄存器返回的,因此返回值没有地址是可以理解的。但是如果函数返回的是一个用户自定义类型的对象,肯定不可能通过寄存器来返回这个对象值的(寄存器大小数量都有限,对象的大小可以非常大),那究竟是怎样返回对象的呢?
- 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
理解lvalue和rvalue的更多相关文章
- [C++] Lvalue and Rvalue Reference
Lvalue and Rvalue Reference int a = 10;// a is in stack int& ra = a; // 左值引用 int* && pa ...
- 理解C++ lvalue与rvalue
一个众所周知的危险错误是,函数返回了一个局部变量的指针或引用.一旦函数栈被销毁,这个指针就成为了野指针,导致未定义行为.而左值(lvalue)和右值(rvalue)的概念,本质上,是理解“程序员可以放 ...
- C中的lvalue和rvalue
该贴子第一条回答虽然浅尝辄止,但还是很有参考价值. https://www.quora.com/What-is-lvalue-and-rvalue-in-C IBM一个简单的说法是: "-通 ...
- L-value 和 R-value.
An L-value is something that can appear on the left side of an equal sign, An R-value is something t ...
- 左值 lvalue,右值 rvalue 和 移动语义 std::move
参考文章: [1] 基础篇:lvalue,rvalue和move [2] 深入浅出 C++ 右值引用 [3] Modern CPP Tutorial [4] 右值引用与转移语义 刷 Leetcode ...
- C++ lvalue(左值)和rvalue(右值)
lvalue(左值)和rvalue(右值) 昨天写代码遇见一个这样的错误:{ "cannot bind non-const lvalue reference of type 'int& ...
- C++11标准之右值引用(rvalue reference)
1.右值引用引入的背景 临时对象的产生和拷贝所带来的效率折损,一直是C++所为人诟病的问题.但是C++标准允许编译器对于临时对象的产生具有完全的自由度,从而发展出了Copy Elision.RVO(包 ...
- C++11中rvalue references的使用
Rvalue references are a feature of C++ that was added with the C++11 standard. The syntax of an rval ...
- 对象复制问题 && lvalue-rvalue && 引用
按值传递实参到函数和函数返回临时变量的副本,函数的效率对执行性能来说至关重要 如果避免这样的复制操作,则执行时间可能会大大缩短. class CMessage { private: char * m_ ...
随机推荐
- 【数据结构(高效)/暴力】Parencodings
[poj1068] Parencodings Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 26686 Accepted ...
- [BalkanOI2016]Lefkaritika
题目大意: 一个n*m的格子上有b个障碍物,现在让你往上面放正方形(长宽在格线上).问可以放多少种边长.位置不同的正方形? 思路: 很容易想到一个O(n^3)的暴力: 首先前缀和,然后枚举某一个顶点和 ...
- [DesignPattern]Builder设计模式
模式的定义 将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示. 模式的使用场景 相同的方法,不同的执行顺序,产生不同的事件结果时: 多个部件或零件,都可以装配到一个对象中,但是 ...
- 初识Tomcat系统架构
俗话说,站在巨人的肩膀上看世界,一般学习的时候也是先总览一下整体,然后逐个部分个个击破,最后形成思路,了解具体细节,Tomcat的结构很复杂,但是 Tomcat 非常的模块化,找到了 Tomcat最核 ...
- 获取asp.net mvc应用程序的根目录
如果使用Server.MapPath(“controllerName”)这样取得的是带控制权名称的目录, 所以要取得上一级目标,如:Server.MapPath("../"),这才 ...
- [典型漏洞分享]exported Android content provider引发的隐私泄露问题
YS android手机APP对外开放多余的content provider,可任意增.删.改和查images数据库表格,导致隐私泄露 问题描述: YS android手机APP使用SQLITE数据库 ...
- Visual Studio中 sln 和 suo 文件
我们通过双击.sln加载出我们的工程,Visual Studio采用两种文件类型(.sln和.suo)来存储解决方案的设置,它们总称为解决方案文件. .sln文件 solution,即解决方案.它引用 ...
- Xcode8从相册选图片
使用Xcode8写自己的东西有一段时间了,在使用Xcode8编程时不得不说我特别喜欢改后的默认字体,哈哈,当然默认字体是可以调回去的,只不过默认的字体感觉看起来比以前舒服了,毕竟不会像之前那么”字正腔 ...
- vmware 下 ubuntu 不能全屏显示 的解决方法
vmware 下 ubuntu 不能全屏显示 在 vmware 下 安装 ubuntu后,默认分辨率是 800 * 600,可以设置以全屏显示: 设置步骤: vmware 下启动 虚拟机,即 启动 u ...
- 【笔记】js原生方法 在元素外部或内部实现添加元素功能(类似jq 的 insert 和 append)
介绍的这个方法是:insetAdjacentHTML() 方法 此方法接收两个参数: 第一个参数必为下列值: beforebegin:在调用的元素外部的前面添加一个目标元素 afterend:在调用元 ...