[转载]C++中的左值和右值

本文详细解释了C++中的左值和右值概念,包括它们的区别、使用场景及如何正确应用前增量和后增量操作符。通过具体实例说明了前增量比后增量更高效的原因。

C++中的左值和右值

[转载自]http://jiang5005.spaces.live.com/blog/cns!619F3DE8AB99988E!111.entry


1.  概念
变量和文字常量都有存储区,并且有相关的类型,区别在于变量是可寻址的;
 
对于每个变量,都有2个值与其相关联:
1>数据值,存储在某个内存地址中,也称右值(rvalue),右值是被读取的值(read value),文字常量和变量都可被用于右值。
2>地址值,即存储数据值的那块内存地址,也称左值(lvalue),文字常量不能被用作左值。
 
2 . 问题
给表达式加上括号: ++a--
结果 ++(a--)
 
这个表达式是非法的,因为前增量操作要求一个可修改的左值,而 "a--" 不是左值(即右值)
 
3 . 前增量和后增量的区别
早期的c语言教材,for循环语句通常写成:
for(int i=0;i<10;i++)
而现在多为:
for(int i=0;i<10;++i)
 
两者有区别吗?
 
a++ 即是返回 a的值,然后变量 a 加 1,返回需要产生一个临时变量类似于
{
       int temp = a;
       a=a+1;
       return temp;  //返回右值
}
 
++a 则为:
{
    a=a+1;
    return &a;    //返回左值
}
 
显然,前增量不需要中间变量,效率更高。 

<think>好的,我现在需要帮助用户理解C++中的的概念,以及它们的定义区别。根据用户提供的引用内容,我需要结合这些资料,并参考之前的对话历史来组织回答。 首先,用户的问题很明确,想了解的定义及区别。用户提供的三个引用都涉及的定义、引用以及现代C++中的特性。之前的对话历史中,用户询问了Web Service项目流程,而当前问题转向C++的基础概念,因此需要确保回答专注于当前主题,不受之前对话的影响。 接下来,我需要整理引用中的信息。引用[1]提到是表达式的基本分类,与内存位置生命周期有关,是理解移动语义的基础。引用[2]强调了理解这两个概念对类型系统表达式求的重要性,并提到了现代C++的影响。引用[3]则讨论了引用移动语义对临时对象处理性能优化的作用。 我需要从基础定义入手,先解释的定义,然后逐步深入它们的特性、判断方法、使用场景,以及现代C++中的变化。可能需要使用示例代码来说明,比如的地址可获取,则是临时。同时,要区分传统C++C++11之后的区别,特别是引用的引入。 此外,用户可能需要了解为什么重要,比如在函数参数传递、移动语义、完美转发等方面的应用。要确保回答结构清晰,分点列出,便于理解。可能还需要比较引用引用的不同,以及它们如何影响代码的性能正确性。 需要检查是否有遗漏的重要点,比如表达式类别在C++11后的扩展(如将亡),但考虑到用户的问题集中在的定义及区别,可能不需要深入这些细节,但可以简要提及。同时,要避免过于技术化的术语,用通俗的语言解释概念,并辅以例子。 最后,生成相关问题,帮助用户进一步学习,比如移动语义、引用的使用场景、完美转发等。确保问题与当前主题紧密相关,并覆盖用户可能感兴趣的扩展方向。</think>### C++ 的定义及区别详解 #### 一、基本定义 1. ** (lvalue)** 指代**具有明确存储位置**的表达式,可理解为"可定位的"。其核心特征: - 可出现在赋运算符侧(C++11后部分受限) - 可获取内存地址(通过`&`运算符) - 具有持久性(生命周期超过当前表达式) ```cpp int a = 10; // a是 int* p = &a; // 正确,a有地址 a = 20; // 可修改 ``` 2. ** (rvalue)** 指代**临时性、无法被寻址**的表达式,其核心特征: - 只能出现在赋运算符侧 - 没有持久存储地址 - 代表计算结果或中间 ```cpp int b = 5 + 3; // 5+3的结果是 string s = "hello";// "hello"是 ``` #### 二、核心区别(C++11前后对比) | 特性 | 传统 | 传统 | C++11扩展 | |---------------------|---------------------|---------------------|---------------------------| | 生命周期 | 超出当前表达式 | 当前表达式结束 | 引用延长生命周期[^3] | | 内存地址 | 明确存在 | 不可获取 | 允许通过&&获取临时对象 | | 典型示例 | 变量名/解引用指针 | 字面量/临时对象 | 移动构造函数的参数 | | 可修改性 | 可修改 | 不可修改 | 通过引用可修改 | #### 三、现代C++的关键演进 1. **引用 (Rvalue Reference)** 使用`T&&`声明,专门绑定到,实现资源转移而非拷贝: ```cpp vector<int> v1 = {1,2,3}; vector<int> v2 = std::move(v1); // v1变为,资源转移给v2 ``` 2. **移动语义 (Move Semantics)** 通过转移资源所有权优化性能: ```cpp class String { public: // 移动构造函数 String(String&& other) : data(other.data), size(other.size) { other.data = nullptr; // 转移资源所有权 } }; ``` 3. **类别扩展** C++11将表达式细分为: - glvalue(广义):包括xvalue(将亡) - rvalue():包括xvalueprvalue(纯) #### 四、实战判断方法 1. **地址测试法**: ```cpp int x = 10; &x; // 合法 → &(x + 5); // 错误 → ``` 2. **生命周期观察**: ```cpp void process(string&& s) { /* s在此函数内有效 */ } process(string("temp")); // 临时string被引用延长生命周期 ``` 3. **类型推导规则**: ```cpp auto&& a = 42; // 42是 → a推导为int&& auto&& b = a; // a是 → b推导为int& ``` #### 五、典型应用场景 1. **函数重载决策**: ```cpp void log(int& val) { cout << "版本"; } void log(int&& val) { cout << "版本"; } int x = 5; log(x); // 调用版本 log(x+2); // 调用版本 ``` 2. **完美转发 (Perfect Forwarding)**: ```cpp template<typename T> void wrapper(T&& arg) { process(std::forward<T>(arg)); // 保持类别不变 } ``` 3. **容器优化**: ```cpp vector<string> vec; vec.push_back("hello"); // 调用移动构造函数,避免字符串拷贝 ```
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值