news 2026/7/25 19:16:22

C++ 左值、右值、左值引用、右值引用

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
C++ 左值、右值、左值引用、右值引用

C++ 左值、右值、左值引用、右值引用

大家好,我是你们的技术博主。今天我们来聊聊C++中一个让很多初学者头疼,但又是进阶必备的概念:左值、右值、左值引用和右值引用。别被这些术语吓到,我会用最通俗的语言,配上可运行的代码,帮你一次搞懂。## 一、什么是左值和右值?在C++中,左值(lvalue)右值(rvalue)是根据对象的持久性可寻址性来区分的。-左值:可以取地址的对象,通常有名字,可以出现在赋值语句的左边。比如变量、数组元素、函数返回的引用等。-右值:临时对象,不能取地址,通常只能出现在赋值语句的右边。比如字面常量(3.14)、表达式的结果(a+b)、函数返回的非引用值等。用一句话总结:左值有持久的内存位置,右值是临时的“过客”。### 示例代码1:区分左值和右值cpp#include <iostream>using namespace std;int main() { int a = 10; // a是左值,10是右值(字面常量) int b = 20; // b是左值 int c = a + b; // a+b的结果是右值(临时值) // 错误示例:右值不能取地址 // int* p = &(10); // 编译错误:不能对右值取地址 // int* q = &(a + b); // 编译错误:不能对临时结果取地址 // 正确示例:左值可以取地址 int* p = &a; // 合法,a是左值 cout << "a的地址: " << p << endl; // 左值可以被赋值 a = 100; // 合法,a是左值 // 10 = a; // 错误:10是右值,不能出现在左边 cout << "a的新值: " << a << endl; cout << "a + b的结果(右值): " << a + b << endl; return 0;}运行结果a的地址: 0x7ffeefbff5a0a的新值: 100a + b的结果(右值): 120## 二、左值引用左值引用,就是绑定到左值的引用。我们平时用的最多的引用类型就是左值引用,用&表示。### 左值引用的特点:- 必须绑定到左值(有名字的变量)- 不能绑定到右值(临时对象)- 引用是原变量的别名,修改引用会改变原变量### 示例代码2:左值引用cpp#include <iostream>using namespace std;int main() { int x = 42; // x是左值 int& ref = x; // ref是左值引用,绑定到x cout << "x = " << x << endl; cout << "ref = " << ref << endl; ref = 100; // 通过引用修改x cout << "修改ref后,x = " << x << endl; // 错误示例:左值引用不能绑定到右值 // int& ref2 = 42; // 编译错误:不能将左值引用绑定到右值 // 常量左值引用可以绑定到右值(特殊规则) const int& cref = 42; // 合法:const引用可以绑定到临时对象 cout << "常量引用绑定到右值: " << cref << endl; return 0;}运行结果x = 42ref = 42修改ref后,x = 100常量引用绑定到右值: 42## 三、右值引用右值引用是C++11引入的新特性,用&&表示。它专门用来绑定到右值(临时对象)。右值引用的出现,主要是为了实现移动语义完美转发。### 右值引用的特点:- 只能绑定到右值(临时对象)- 可以延长临时对象的生命周期- 主要用于移动构造函数和移动赋值运算符### 示例代码3:右值引用cpp#include <iostream>#include <string>using namespace std;void processValue(int& val) { cout << "左值引用版本,val = " << val << endl;}void processValue(int&& val) { cout << "右值引用版本,val = " << val << endl;}int main() { int a = 10; int b = 20; processValue(a); // 调用左值引用版本 processValue(a + b); // 调用右值引用版本(a+b是临时值) processValue(100); // 调用右值引用版本(100是字面常量) // 右值引用变量本身是左值 int&& rref = 42; // rref绑定到右值42 // 但rref本身是左值(有名字、可寻址) processValue(rref); // 调用左值引用版本,因为rref是左值 // 使用std::move可以将左值转为右值 processValue(std::move(a)); // 调用右值引用版本 return 0;}运行结果左值引用版本,val = 10右值引用版本,val = 30右值引用版本,val = 100左值引用版本,val = 42右值引用版本,val = 10## 四、为什么需要右值引用?右值引用的核心价值在于移动语义。传统的拷贝操作会复制数据,而移动操作可以“偷取”临时对象的资源,避免不必要的内存拷贝,提升性能。### 示例代码4:移动语义与拷贝构造cpp#include <iostream>#include <vector>#include <string>using namespace std;class MyVector {public: int* data; size_t size; // 构造函数 MyVector(size_t n) : size(n) { data = new int[n]; cout << "构造函数,分配了 " << n << " 个整数" << endl; } // 拷贝构造函数(深拷贝) MyVector(const MyVector& other) : size(other.size) { data = new int[size]; copy(other.data, other.data + size, data); cout << "拷贝构造函数,深拷贝 " << size << " 个整数" << endl; } // 移动构造函数(偷取资源) MyVector(MyVector&& other) noexcept : data(other.data), size(other.size) { other.data = nullptr; other.size = 0; cout << "移动构造函数,偷取了 " << size << " 个整数" << endl; } ~MyVector() { delete[] data; cout << "析构函数" << endl; }};int main() { vector<MyVector> vec; cout << "--- 创建临时对象并插入 ---" << endl; vec.push_back(MyVector(10)); // 创建临时MyVector,然后移动或拷贝 cout << "\n--- 使用std::move ---" << endl; MyVector v1(20); vec.push_back(std::move(v1)); // 将左值转为右值,触发移动构造 cout << "\n程序结束" << endl; return 0;}运行结果--- 创建临时对象并插入 ---构造函数,分配了 10 个整数移动构造函数,偷取了 10 个整数析构函数--- 使用std::move ---构造函数,分配了 20 个整数移动构造函数,偷取了 20 个整数程序结束析构函数析构函数## 五、总结通过本文,我们学习了C++中左值、右值、左值引用和右值引用的核心概念:1.左值:有持久内存位置的对象,可以取地址,通常有名字。2.右值:临时对象,不能取地址,通常是字面常量或表达式结果。3.左值引用:绑定到左值的引用,用&表示,不能绑定到右值(除了const引用)。4.右值引用:绑定到右值的引用,用&&表示,是C++11的新特性,用于实现移动语义。右值引用的出现,让C++程序员能够更精细地控制资源管理,通过移动语义避免不必要的拷贝,显著提升程序性能。在实际开发中,合理使用std::move和移动构造函数,可以让你的代码既高效又优雅。记住一句话:左值引用绑定到“有家”的对象,右值引用绑定到“流浪”的临时对象。理解了这个比喻,你就掌握了这些概念的精髓。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/25 19:13:07

借助模型广场与统一API简化多模型技术选型与测试过程

借助模型广场与统一API简化多模型技术选型与测试过程 面对众多大语言模型&#xff0c;技术决策者常常陷入选择困境&#xff1a;哪个模型更适合我的业务场景&#xff1f;效果和成本如何平衡&#xff1f;传统的选型方式往往需要在不同厂商的API、文档和计费模式之间反复切换&…

作者头像 李华
网站建设 2026/7/25 19:12:42

终极Obsidian导出指南:3步将你的知识库迁移到任何平台

终极Obsidian导出指南&#xff1a;3步将你的知识库迁移到任何平台 【免费下载链接】obsidian-export Rust library and CLI to export an Obsidian vault to regular Markdown 项目地址: https://gitcode.com/gh_mirrors/ob/obsidian-export 你是否曾为Obsidian笔记的&q…

作者头像 李华
网站建设 2026/7/25 19:08:29

3步解决《十字军之王II》中文乱码:双字节字符补丁完全指南

3步解决《十字军之王II》中文乱码&#xff1a;双字节字符补丁完全指南 【免费下载链接】CK2dll Crusader Kings II double byte patch /production : 3.3.4 /dev : 3.3.4 项目地址: https://gitcode.com/gh_mirrors/ck/CK2dll 还在为《十字军之王II》中无法显示中文、日…

作者头像 李华
网站建设 2026/7/25 19:08:09

Dev-C++与C语言入门:从环境搭建到高效编程实践指南

1. 项目概述&#xff1a;为什么Dev-C依然是C语言初学者的首选如果你正准备开始学习C或C编程&#xff0c;大概率会从网上搜索“C语言用什么软件”开始。在众多推荐中&#xff0c;一个名字反复出现——Dev-C。这个诞生于上世纪90年代末的集成开发环境&#xff08;IDE&#xff09;…

作者头像 李华
网站建设 2026/7/25 19:06:27

世界模型:AI理解物理规律的关键技术解析

1. 项目概述&#xff1a;当AI学会理解物理世界去年我在调试一个机械臂抓取系统时&#xff0c;发现传统视觉算法对透明物体的识别率始终低于60%。直到引入世界模型&#xff08;World Model&#xff09;框架后&#xff0c;系统突然能预测玻璃杯的折射效果了——这让我意识到&…

作者头像 李华
网站建设 2026/7/25 19:06:22

微软官方Windows Server 2008 R2 VHD镜像:快速搭建测试环境的完整指南

这次我们来看一个微软官方提供的 Windows Server 2008 R2 企业版 VHD 镜像。对于需要快速搭建测试环境、学习服务器配置或进行概念验证的 IT 从业者、学生和开发者来说,这个预配置的虚拟硬盘文件是一个极佳的起点。它最大的特点就是“开箱即用”,省去了从零安装操作系统、打补…

作者头像 李华