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

C++ 左值引用与右值引用介绍

C++ 左值引用与右值引用详解

在 C++ 的类型系统中,引用(reference) 是一种为已有对象起别名的机制。在早期(C++98/03)中,C++ 只有 左值引用(lvalue reference),主要用于函数参数传递、返回值以及避免拷贝。到了 C++11,引入了 右值引用(rvalue reference),为完美转发(perfect forwarding)和移动语义(move semantics)提供了语言支持,大大提升了性能和灵活性。


一、左值与右值的基本概念

在解释左值引用和右值引用之前,需要弄清楚 左值(lvalue)右值(rvalue) 的含义。

1. 左值(lvalue)

  • 左值表示在表达式结束后仍然存在的对象,可以取地址,有名字。
  • 特点:可以出现在赋值号的左边(其实是因为可寻址,而不是单纯因为在左边)。
  • 常见例子:
int x = 10; // x 是一个左值
x = 20;     // 左值可以出现在赋值号的左边
&x;         // 可以取地址

2. 右值(rvalue)

  • 右值表示表达式结束后不再存在的临时对象,通常不能取地址,没有名字。
  • 特点:只能出现在赋值号的右边(通常是字面量、表达式结果等)。
  • 常见例子:
10;         // 字面量是右值
x + 5;      // 表达式结果是右值
std::string("Hello"); // 临时对象是右值

二、左值引用(lvalue reference)

1. 定义

左值引用的语法形式是在类型名后面加上 &

int a = 10;
int& ref = a;  // ref 是 int 类型的左值引用,绑定到 a

此时 ref 就是 a 的别名,对 ref 的修改就是对 a 的修改。

2. 特点

  • 只能绑定到左值
  • 一旦绑定,引用不可更换绑定对象。
  • 常用于函数参数传递,避免拷贝,提高性能。

3. 示例

void increment(int& n) {n++;
}int main() {int x = 5;increment(x);  // x 被修改为 6
}

三、右值引用(rvalue reference)

1. 定义

右值引用的语法形式是在类型名后面加上 &&

int&& rref = 10;  // rref 绑定到右值 10

右值引用可以绑定到临时对象(右值),使得我们可以在它被销毁之前对其进行修改或“移动”。

2. 特点

  • 只能绑定到右值(包括字面量、临时对象、表达式结果等)。
  • 常用于移动语义完美转发
  • 避免不必要的深拷贝,提高性能。

3. 示例

#include <iostream>
#include <vector>void printVector(std::vector<int>&& v) {std::cout << "Size: " << v.size() << '\n';
}int main() {std::vector<int> tmp = {1, 2, 3};printVector(std::move(tmp)); // 将 tmp 转换为右值引用
}

四、移动语义与右值引用

在 C++98/03 中,如果我们返回一个大对象,会产生不必要的深拷贝:

std::string getStr() {std::string s = "Hello";return s; // 旧标准中可能拷贝一次
}

C++11 引入了 移动构造函数右值引用,允许“窃取”临时对象的资源,而不是复制。

移动构造函数示例

#include <iostream>
#include <string>class MyString {char* data;
public:MyString(const char* s) {data = new char[strlen(s)+1];strcpy(data, s);}// 移动构造函数MyString(MyString&& other) noexcept {data = other.data;other.data = nullptr;std::cout << "Moved!\n";}~MyString() { delete[] data; }
};int main() {MyString a("Hello");MyString b(std::move(a)); // 调用移动构造
}

五、完美转发与 std::forward

当我们写一个模板函数时,可能希望保留实参的值类别(左值或右值)。使用 右值引用 + 引用折叠规则 + std::forward 可以实现完美转发。

#include <utility>
#include <iostream>void process(int& x)  { std::cout << "Lvalue\n"; }
void process(int&& x) { std::cout << "Rvalue\n"; }template<typename T>
void forwarder(T&& arg) {process(std::forward<T>(arg));
}int main() {int a = 5;forwarder(a);        // 输出 Lvalueforwarder(10);       // 输出 Rvalue
}

六、引用折叠规则

C++ 的引用折叠规则规定:

  • T& & 折叠为 T&
  • T& && 折叠为 T&
  • T&& & 折叠为 T&
  • T&& && 折叠为 T&&

这使得 万能引用(universal reference)(或者叫转发引用 forwarding reference)成为可能。


七、注意事项

  1. 右值引用不是万能的:绑定到右值意味着你可以修改它,但并不是强制要移动它。
  2. 使用 std::movestd::move 并不移动对象,只是将左值强制转换为右值引用。
  3. 警惕悬挂引用:右值引用绑定到临时对象,如果临时对象销毁,引用就悬空。
  4. 移动后对象可用但状态不确定:移动语义通常会清空被移动对象的内部资源,但允许它被安全析构。

八、总结对比表

特性左值引用 (T&)右值引用 (T&&)
可绑定对象类型左值右值
常见用途参数传递,避免拷贝移动语义,完美转发
C++ 引入版本C++98C++11
是否可更换绑定对象
是否支持取地址

文章转载自:

http://00flOKXA.xpqdf.cn
http://2g0DT0CB.xpqdf.cn
http://8DqCDirA.xpqdf.cn
http://XZsGUa0I.xpqdf.cn
http://4atOUrX6.xpqdf.cn
http://ripYHYkq.xpqdf.cn
http://hcjKfq5K.xpqdf.cn
http://wrPK27aB.xpqdf.cn
http://bNp6Hexv.xpqdf.cn
http://t7ujJ3jS.xpqdf.cn
http://G0lSX7GS.xpqdf.cn
http://tA1sxpcw.xpqdf.cn
http://RUnSjb5R.xpqdf.cn
http://rCkQZyoS.xpqdf.cn
http://g8Qypa56.xpqdf.cn
http://VzuxXLph.xpqdf.cn
http://q26Jo0TV.xpqdf.cn
http://Sxb9odNO.xpqdf.cn
http://J2H2SY9M.xpqdf.cn
http://scGQ7T73.xpqdf.cn
http://657ap2jE.xpqdf.cn
http://rFuGnQ5P.xpqdf.cn
http://AeawLaaq.xpqdf.cn
http://zampYOrc.xpqdf.cn
http://Aoj5qZsr.xpqdf.cn
http://RZsGCika.xpqdf.cn
http://Lm0zgXhw.xpqdf.cn
http://g7No5Tu4.xpqdf.cn
http://xlUBEv5G.xpqdf.cn
http://b1Xwvxkv.xpqdf.cn
http://www.dtcms.com/a/363673.html

相关文章:

  • MySQL数据库精研之旅第十五期:索引的 “潜规则”(下)
  • OpenCV Python
  • 0825-0829 | 大模型方向周报:多模态模型研究、训练与优化策略、安全与对齐等方向
  • SQL Server--提取性能最差的查询
  • 阿里云国际代理商:如何重置阿里云服务器密码?
  • 阿里云日志服务之WebTracking 小程序端 JavaScript SDK (阿里SDK埋点和原生uni.request请求冲突问题)
  • 现代CPU设计哲学——加载/存储(Load-Store)架构
  • 作为软件专业学生,我眼中新架构实践的‘稳’与‘进’
  • NLP学习系列 | Transformer代码简单实现
  • MySQL 事务隔离与 MVCC
  • 鸿蒙权限崩溃?一招解决闪退难题
  • 自建局域网gitlab如何修改提交时间
  • 365 天技术创作手记:从一行代码到四万同行者的相遇
  • 基本IP保护 Swagger UI 的中间件
  • Flutter doctor
  • 试用Augment编写python脚本实现智能家居3D环境交互响应
  • Vite + React + Tailwind v4 正确配置指南(避免掉进 v3 的老坑)
  • MyBatis 日志与调试技巧:让 SQL 执行过程完全透明
  • Node.js 命令行交互王者:inquirer 模块实战指南
  • 你们公司的 QPS 是怎么统计出来的?这 5 种常见方法我踩过一半的坑!
  • LazyLLM教程 | 第7讲:检索升级实践:亲手打造“更聪明”的文档理解系统!
  • Text2SQL与DataAgent技术深度对比与实践指南
  • 【算法笔记 day six】二分算法的第三部分
  • Linux下Qt样式配置
  • Qt内存映射到文件,解决打开大文件占用内存高的问题
  • Qt5 多媒体大纲
  • 基础算法之二分算法 --- 1
  • 基于SpringBoot的校园资料分享平台
  • 力扣242:有效的字母异位词
  • 漏扫工具使用