一个众所周知的危险错误是,函数返回了一个局部变量的指针或引用。一旦函数栈被销毁,这个指针就成为了野指针,导致未定义行为。而左值(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. Office 365开发环境概览

    本文于2017年3月26日首发于LinkedIn,原文链接请参考这里 本系列文章已经按照既定计划在每周更新,此前的几篇文章如下 Office 365 开发概览系列文章和教程 Office 365开发概 ...

  2. 用js实现图片的无缝滚动效果

    实现图片的无缝滚动就是要让你的图片集在一定时间里自动切换,那就需要js里的定时器来控制时间. js中关于定时器的方法有两种:setTimeout和setInterval.它们接收的参数是一样的,第一个 ...

  3. 微服务--webapi实现,脱离iis,脱离tomcat

    前言 微服务,顾名思义就是微小的单一的服务程序,单一流程,单一发布,开发和部署都可独立: 这是我的理解: 但基于web的服务,不管是webservice还是webapi等类似的服务都需要基于iis或者 ...

  4. 02 nodejs命令参数(NodeJS基础入门)

    声明:本文章可供有一定js基础的朋友参考nodejs入门,本文未讲解nodejs的安装,如有需要的同学可以加QQ3382260752找我,进行交流学习. 建议使用开发软件:webstorm或hbuil ...

  5. 深入分析Java单例模式的各种方案

    单例模式 Java内存模型的抽象示意图: 所有单例模式都有一个共性,那就是这个类没有自己的状态.也就是说无论这个类有多少个实例,都是一样的:然后除此者外更重要的是,这个类如果有两个或两个以上的实例的话 ...

  6. BinarySearch的一些注意事项

    BinarySearch原理比较简单,不过在处理实际问题的过程中需要注意几个小问题: 1. 找出有序数组中第一个为某特定值的数,以及没找到则返回-1 2. 找出有序数组中最后一个为某特定值的数,以及没 ...

  7. CSS3选择器~一看吓一跳,这么多不会

    复习CSS时发现很多选择器不会,因为平时很少用到.现在干脆一不做二不修,全部温习一遍.本文参考http://css.doyoe.com/. 一.元素选择器 图片来自:http://css.doyoe. ...

  8. js alert(“”)弹框 自定义样式

    首先用css渲染一个样式 #msg{ height: 2rem; text-align: center; position: fixed; top: 50%; margin-top: -1rem; l ...

  9. 如何使用第三方webservice

    webservice地址后加wdls 生成后把文件名改为wdsl 调用方式: 1.添加webservice引用: 2.生成代理类的方法(本人比较喜欢用这种方式): 使用cmd命令行: a.通过webs ...

  10. C#图解教程-方法参数笔记(上)

    一晃大学四年要过去了,期间乱点了很多技能点, 导致每一项技能都只是处于入门阶段.为了将C#作为我的主要技能,准备恶补相关姿势(知识),通过各种技术论坛的推荐,找到了<C#图解教程>这本书. ...