当前位置: 首页 > news >正文

C++ 左值和右值 —— 奇牛+Gemini

C++ 左值和右值 —— 奇牛+Gemini

C++ 中的值类别是表达式(Expression)的静态语法属性,而非对象(Object)或物理内存的属性。其分类体系随语言标准的演进而重构,核心驱动力是 C++11 引入的移动语义(Move Semantics)

1. C++98二分法及其局限性

在 C++98 及更早的时期,C++ 继承了 C 语言的分类思想,采用简单的二分法:

  • lvalue(左值):可以出现在赋值运算符=左边或右边的表达式。

    • 它指向内存中一个明确的位置(有内存地址,可以通过&取地址)
    • 在该语句结束后依然存在(生命周期横跨当前语句)
  • rvalue(右值)只能出现在赋值运算符=右边的表达式。

    • 通常为临时数据(不可取地址)
    • 完整表达式结束后销毁。

局限性:无法准确描述 std::move(obj) 这种“具有明确内存身份,但允许被剥夺资源”的表达式。

2. 现代 C++ 的范式转换:核心矛盾与特征维度

C++11 引入了右值引用(&&)和移动语义,旨在“偷取”即将销毁对象的资源以提升性能。此时面临一个逻辑矛盾:

std::move(obj) 这样的表达式,它引用的是一个实实在在拥有内存地址和身份的对象(具备 C++98 左值的特征),但我们又明确允许从它那里安全地剥夺资源(具备 C++98 右值的特征)。

为了精确描述这种“既像左值又像右值”的表达式,C++ 委员会之父 Bjarne Stroustrup 提出基于两个独立的特征维度对表达式重新分类:

  • 拥有身份 (has identity - $i$):可通过指针、引用或取地址操作(&)确定表达式指代的内存实体。
  • 可被移动 (can be moved from - $m$):允许安全地将其底层资源转移给其他对象,而不破坏程序一致性。

基于这两个维度,现代 C++ 的表达式被细分为 三大基础类别两大复合类别(构成了一个著名的“W”型树状分类)

3. 现代 C++ 表达式分类体系 (W型树状结构)

基于上述维度,表达式被严密划分为三大基础类别(互斥)和两大复合类别。

3.1 三大基础类别(Mutually Exclusive)

  1. lvalue(左值)有身份,且不可被移动。

    传统意义上的变量、函数、返回左值引用的函数调用等。你明确知道它在哪里,且不能随便剥夺它的资源。

  2. prvalue(纯右值,Pure rvalue)无身份,且可被移动。

    传统的临时变量和字面量(字符串字面量除外)。比如计算 1 + 2 产生的临时结果,它没有名字,用完即弃,资源可以被随意夺取。

  3. xvalue(将亡值,eXpiring value)有身份,且可被移动。

    • 这是 C++11 诞生的新物种。 它表示那些虽然在内存中有明确确定的实体(有身份),但其生命周期即将结束,或者开发者通过显式转换(如 std::move)承诺可以被剥夺资源的表达式。

3.2 两大复合类别

  1. glvalue(广义左值,Generalized lvalue)= lvalue + xvalue

    包含了所有有身份的表达式。广义左值的核心特征是:支持多态,你可以通过它调用虚函数而不会发生对象切片。

  2. rvalue(右值)= prvalue + xvalue

    包含了所有可被移动的表达式。这是现代 C++ 重载解析(Overload Resolution)时,匹配右值引用(T&&)参数的核心集合。

4. 示例代码

#include <iostream>
#include <string>
#include <utility>class Resource {};
Resource createResource() { return Resource(); }int main() {int a = 10; std::string s1 = "Hello";std::string s2 = "World";// 1. lvalue (左值) 示例// 表达式 'a', 's1', 's2' 都是左值。有明确的内存位置,不能被隐式移动。a = 20; // 2. prvalue (纯右值) 示例// 表达式 '10', 'createResource()' 是纯右值。// 它们不占有持久的内存地址(尝试 &10 会导致编译器报错),仅用作初始化或计算的中间量。int b = 10; Resource r = createResource(); // 3. xvalue (将亡值) 示例// 表达式 'std::move(s1)' 是将亡值。// s1 本身是左值(有身份),通过 std::move 显式将其转换为右值引用返回类型。// 该表达式告诉编译器:s1 的身份还在,但其内部资源可以被 s3 拿走。std::string s3 = std::move(s1); // 表达式 'static_cast<std::string&&>(s2)' 也是将亡值,std::move 本质就是这个 static_cast。std::string s4 = static_cast<std::string&&>(s2);return 0;
}
http://www.jsqmd.com/news/795843/

相关文章:

  • 基于HCNR200/201的高精度模拟信号隔离电路设计与实践
  • Docker镜像构建进化论:从手工操作到多阶段构建的实战指南
  • PostgreSQL数据清洗实战:用string_agg合并地址字段,我这样整理混乱的客户信息
  • 【赵渝强老师】金仓数据库的运行日志文件
  • 5步精通League Akari:高效解锁英雄联盟LCU工具箱的完整指南
  • 码率控制方法详解
  • BetterRTX终极教程:5分钟免费提升Minecraft画质的完整方案
  • 3分钟高效获取百度网盘提取码:开源自动化工具实战指南
  • NoFences:开源免费的Windows桌面围栏管理工具,让杂乱桌面瞬间井然有序
  • pip install -r requirements.txt报错:Collecting PyGObject (from -r requirements.txt (line 26))...如何解决?
  • 用Python+Elasticsearch实时处理Websocket股票数据:保姆级配置与实战分析
  • 考虑电解槽变载启停特性与阶梯式碳交易机制的综合能源系统优化调度研究(Matlab代码实现)
  • League-Toolkit:基于模块化架构的英雄联盟客户端自动化工具深度解析
  • 科技早报|2026年5月11日:AI Agent 开始补验证、分工和落地这三道工程题
  • 从零打造USB-C一拖二数据线:硬件拆解与引脚焊接实战
  • 论mysql的redo_log和bin_log,redis的RDB和AOF的类似记忆
  • Visual C++运行库一键修复工具:告别DLL错误和软件崩溃的终极解决方案
  • 【信息科学工程学】【社会科学】 第五十五篇 人的利益规则04
  • Akari助手:基于LCU API的自动化竞技辅助框架
  • 2026年论文AI率太高怎么办?这几招帮你高效降到安全线 - 降AI实验室
  • 本周补题5/4--5/10
  • 用 python 和 java 分别写出10道经典题
  • 终极指南:如何用Legacy-iOS-Kit拯救你的老旧iPhone/iPad?一站式降级、越狱与备份工具全解析
  • Dell G15终极散热指南:开源温度控制中心完全解析
  • vSphere/ESXi安装虚拟机的10种方法
  • 2026年保定装修厂家口碑推荐榜:保定整装定制、保定家装、保定商业美陈装修、保定别墅设计装修、保定门店装修厂家选择指南 - 海棠依旧大
  • Steam成就管理终极指南:SAM开源工具完整使用教程
  • 宇树GO2机器人ROS2控制实战:从零到自主导航的完整指南
  • 【信息科学工程学】【社会科学】 第五十五篇 人的利益规则05——行业篇04
  • 告别Keil‘瞎眼’调试:手把手教你用CLion+STM32CubeMX配置DSP库(附完整CMakeLists)