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

空泛的讨论先到这里,先看一段会报错的代码:

#include <iostream>

using std::cout;
using std::endl; int foo(int &a) {
return a;
} int main() {
int a = ;
cout << &a << endl;
int *p = &foo(a);
}

这里,对foo(a)取地址会引起错误: "lvalue required as left operand of assignment".字面理解是,&取地址运算符只能获取左值的地址。

毫无疑问的是,foo(a)的值是存在的,是数值1。之所以报错,是因为编译器认为它不是左值,不允许程序员获取它存放的地址。

我对这点标准的理解是:

获取一个临时空间的地址通常意味着要对这块内存赋值。在C++程序中,临时空间的销毁时机是不确定(undefined)的,它随时被用于其他临时空间的存储。于是程序员不允许使用这块空间。联系之前总结的堆栈概念,可以对C++中的变量存储有更深的理解。

在堆栈概念一文,我小结了C++程序中数据可以存在三个地方:

1. 函数栈,在函数体内的定义的变量

2. 堆,特别指使用new,malloc获取的内存空间

3. 静态数据区,即.data 和.bss

对于lvalue的通俗描述,是“具有确定地址的非临时对象”,而不满足lvalue定义的值均被认为是rvalue。换句话说,C++程序里面出现的值,非左即右。下面我们分析一下这三个存放数据的区域里面可以被使用的值的情况:

堆

堆的空间上的变量完全由程序员申请和管理的,所以它们都有明确的地址,是可以放心使用的左值。

静态数据区

对于静态数据区,尽管存放的位置是固定的,但里面的数据并不能认为都是左值。主要是因为里面有“字面值”,包括const所实现的常量,即静态存储而不能被修改的值。

函数栈

当函数调用发生的时候,系统会创建函数栈,保留上下文,函数调用结束的时候,函数栈内的变量会被销毁。函数体里面定义的变量是左值,而临时变量是右值。

拓展

C++ 11标准,为了更好地利用临时变量,提出Rvalue Reference,对应的的实现是move semantics (转移语意)和Perfect Forwarding(完美转发)。对这些新特性还不了解,暂时不写。

参考:

http://www.cnblogs.com/dejavu/archive/2012/09/02/2667640.html

http://stackoverflow.com/questions/230584/where-are-variables-in-c-stored

http://eli.thegreenplace.net/2011/12/15/understanding-lvalues-and-rvalues-in-c-and-c

理解C++ lvalue与rvalue的更多相关文章

  1. [C++] Lvalue and Rvalue Reference

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

  2. 理解lvalue和rvalue

    今天看C++模板的资料,里面说到lvalue,rvalue的问题,这个问题以前也看到过,也查过相关资料,但是没有考虑得很深,只知道rvalue不能取地址,不能赋值等等一些规则.今天则突然有了更深层次的 ...

  3. C中的lvalue和rvalue

    该贴子第一条回答虽然浅尝辄止,但还是很有参考价值. https://www.quora.com/What-is-lvalue-and-rvalue-in-C IBM一个简单的说法是: "-通 ...

  4. 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 ...

  5. 左值 lvalue,右值 rvalue 和 移动语义 std::move

    参考文章: [1] 基础篇:lvalue,rvalue和move [2] 深入浅出 C++ 右值引用 [3] Modern CPP Tutorial [4] 右值引用与转移语义 刷 Leetcode ...

  6. C++ lvalue(左值)和rvalue(右值)

    lvalue(左值)和rvalue(右值) 昨天写代码遇见一个这样的错误:{ "cannot bind non-const lvalue reference of type 'int& ...

  7. C++11中rvalue references的使用

    Rvalue references are a feature of C++ that was added with the C++11 standard. The syntax of an rval ...

  8. c++ 左值 和 右值

    什么是lvalue, 什么是rvalue? lvalue: 具有存储性质的对象,即lvalue对象,是指要实际占用内存空间.有内存地址的那些实体对象,例如:变量(variables).函数.函数指针等 ...

  9. 对象复制问题 && lvalue-rvalue && 引用

    按值传递实参到函数和函数返回临时变量的副本,函数的效率对执行性能来说至关重要 如果避免这样的复制操作,则执行时间可能会大大缩短. class CMessage { private: char * m_ ...

随机推荐

  1. Spring execution表达式

    execution(modifiers-pattern? ret-type-pattern declaring-type-pattern? name-pattern(param-pattern) th ...

  2. Luogu2723丑数Humble Numbers【归并排序】

    Luogu2723丑数Humble Numbers 题目背景 对于一给定的素数集合 S = {p1, p2, ..., pK},考虑一个正整数集合,该集合中任一元素的质因数全部属于S.这个正整数集合包 ...

  3. 【Egret】里使用iframe标签达到内嵌多个web界面

    目的:Egret里使用iframe标签达到内嵌多个web界面,模式相当于主swf调用N个子swf的效果: 目前在做项目过程中,在使用iframe的时候,碰到了一些功能需求,以及解决方法如下: 一..在 ...

  4. swfobject.js加载swf,关于是否加加载完成;

    这几个帖子可以参考下 http://bbs.9ria.com/forum.php?mod=viewthread&page=1&tid=38913 http://bbs.9ria.com ...

  5. 使用 SLF4J + LogBack 构建日志系统(转)

    转载自:http://www.cnblogs.com/mailingfeng/p/3499436.html 上次我们讨论了如何选择一个好的开源日志系统方案,其中的结论是:使用 SLF4J + LogB ...

  6. EDP转接IC NCS8805:RGB/LVDS转EDP芯片,带Scaler

    RGB/LVDS-to-eDP Converter w/ Scaler1 FeaturesEmbedded-DisplayPort (eDP) Output1/2/4-lane eDP @ 1.62/ ...

  7. Android报错:WindowManager$BadTokenException: Unable to add window -- window has already been added

    很久之前测试通过的代码,现在手机升级了Android7.0后一运行就崩溃,报出这样的错误,具体错误如下: Process: com.example.sho.android_anti_theft, PI ...

  8. Map和Set

    JavaScript的默认对象表示方式{}可以视为其他语言中的Map或Dictionary的数据结构,即一组键值对. 但是JavaScript的对象有个小问题,就是键必须是字符串.但实际上Number ...

  9. 严格模式下的javascript

    arguments: ECMA5移除了实参对象(arguments),在非严格模式下函数里的arguments只是一个标识符,在严格模式下它变成了保留字.严格模式下无法使用arguments作为形参名 ...

  10. Java中boolean类型占用多少个字节

    为什么要问这个问题,首先在Java中定义的八种基本数据类型中,除了其它七种类型都有明确的内存占用字节数外,就boolean类型没有给出具体的占用字节数,因为对虚拟机来说根本就不存在 boolean 这 ...