一个众所周知的危险错误是,函数返回了一个局部变量的指针或引用。一旦函数栈被销毁,这个指针就成为了野指针,导致未定义行为。而左值(lvalue)和右值(rvalue)的概念,本质上,是理解“程序员可以放心使用的变量”。
空泛的讨论先到这里,先看一段会报错的代码:
#include
using std::cout;
using std::endl;
int foo(int &a) {
return a;
}
int main() {
int a = 1;
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(完美转发)。对这些新特性还不了解,暂时不写。
理解C++ lvalue与rvalue
发表于:2017-08-08
作者:Kinsang
来源:
 相关文章
让你的 C++ 代码变得更加高效和优雅... C++性能优化指南:让你的程序飞起来! 指针变量在C/C++中的内存占用 C++ Module详解:模块化编程终极指南 深入学习 C++编程,数据结构与算法关系 C++编程入门!五个学习阶段让你从新手...- 周排行
- 月排行
-   缓存技术:加速应用,提高用户体验
-   六个好用的在线代码编辑器,你选哪个?
-   C++简单String类的实现
-   适合Java开发者学习的Python入门教程
-   在软件开发中实施AI与敏捷管理的九点建议
-   快速提升 UI 设计效果的 6 个小技巧
-   如何将SAST融入DevSecOps流程中?
-   微服务架构:构建高灵活性的分布式系统
-   这 14 个 VSCode 插件,让你写代码如同神一般
-   最全的C++资源大全,纯干货!
-   智能可穿戴设备的主要测试步骤
-   衡量软件产品质量的 14 个指标
-   自动化神器AutoIt,告别重复劳动
-   缓存技术:加速应用,提高用户体验