一个众所周知的危险错误是,函数返回了一个局部变量的指针或引用。一旦函数栈被销毁,这个指针就成为了野指针,导致未定义行为。而左值(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. [麻雀虽小]记 简易Markdown阅读器 开发全过程

    [麻雀虽小]记 简易Markdown阅读器 开发全过程 [TOC] 序言 项目地址: https://github.com/didikee/MDReader 测试文章地址: 2017 Android ...

  2. jQuery Ajax 实例 全解析(转)

    1. load( url, [data], [callback] ) :载入远程 HTML 文件代码并插入至 DOM 中. url (String) : 请求的HTML页的URL地址. data (M ...

  3. 【C语言】模拟实现printf函数(可变参数)

    一.printf函数介绍 printf功能 printf函数是格式化输出函数,一般用于向标准输出设备按规定格式输出信息. printf原型 int printf( const char* format ...

  4. 老李分享:loadrunne动态查询db2数据库

    老李分享:loadrunne动态查询db2数据库   poptest老李认为性能测试脚本开发不仅仅涉及到脚本开发的技术层面,同时也要对一些其他技术有所了解动态链接库的技术,线程安全等等,建议在做下面的 ...

  5. [翻译] 使用ElasticSearch,Kibana,ASP.NET Core和Docker可视化数据

    原文地址:http://www.dotnetcurry.com/aspnet/1354/elastic-search-kibana-in-docker-dotnet-core-app 想要轻松地通过许 ...

  6. gulp基于seaJs模块化项目打包实践【原创】

    公司还一直在延续使用jq+seajs的技术栈,所以只能基于现在的技术栈进行静态文件打包,而众所周知seajs的打包比较"偏门",在查了不少的文档和技术分享后终于琢磨出了自己的打包策 ...

  7. lua 条件控制

    lua 条件控制 if 语句 结构 if (condition) then statements end 示例程序 local a = 10 if (a > 1) then print(&quo ...

  8. HubbleDotNet 最新绿色版,服务端免安装,基于eaglet 最后V1.2.8.9版本开发,bug修正,支持一键生成同步表

    HubbleDotNet 是一个基于.net framework 的开源免费的全文搜索数据库组件.开源协议是 Apache 2.0.HubbleDotNet提供了基于SQL的全文检索接口,使用者只需会 ...

  9. Android -- 贝塞尔实现水波纹动画(划重点!!)

    1,昨天看到了一个挺好的ui效果,是使用贝塞尔曲线实现的,就和大家来分享分享,还有,在写博客的时候我经常会把自己在做某种效果时的一些问题给写出来,而不是像很多文章直接就给出了解决方法,这里给大家解释一 ...

  10. 在Delphi下使用迅雷APlayer组件进行免注册开发

    之前都是用的delphi下的dspack进行的视频开发,这个组件其实很好用,就是找解码器麻烦点,而且还得在客户的计算机上使用RegSvr32.exe也注册解码器,要不有可能播放不了. 结果在查找合适的 ...