RVO是C++编译器对按值返回对象时的优化技术,直接在调用方内存构造对象,省略临时对象及拷贝/移动构造;C++17强制纯右值返回的拷贝省略,NRVO仍为可选优化。

RVO(Return Value Optimization,返回值优化)是C++编译器在函数按值返回对象时,自动跳过临时对象构造和拷贝过程的一种关键性能优化技术。它不是靠程序员手动写代码触发的“技巧”,而是编译器根据语义合法地“省掉多余步骤”——直接在调用方准备接收返回值的内存位置上构造对象,只调用一次构造函数,不调用拷贝或移动构造函数,也不析构中间临时对象。
RVO 和 NRVO 的区别
RVO 分两类,核心差异在于返回表达式是否具名:
-
Unnamed RVO(无名RVO):函数直接返回一个临时对象,比如
return MyClass();或return func();(func 返回临时对象)。编译器可将该临时对象直接构造在调用者的返回目标位置。 -
NRVO(Named Return Value Optimization,命名返回值优化):函数内定义了一个具名局部变量(如
MyClass obj;),并在单一 return 语句中返回它(return obj;)。此时编译器尝试把obj直接构造在外部目标内存中,避免拷贝。但 NRVO 触发条件更严格,比如多个 return 分支、中途修改返回变量、或存在异常路径都可能抑制它。
RVO 在 C++17 中的变化
C++17 将部分 RVO 场景升级为强制要求(即“保证拷贝省略”,guaranteed copy elision):
- 当函数返回一个与返回类型相同的纯右值(如
return MyClass{...};)时,编译器必须省略拷贝/移动构造,直接构造到目标位置。 - 这不再是“可选优化”,而是标准行为,意味着你写的代码在所有合规编译器中都会获得这一优化,无需依赖编译器开关或特定版本。
- 注意:NRVO(对具名变量的优化)仍属于鼓励但不强制的优化,各编译器实现程度略有差异。
为什么 RVO 对性能很重要
没有 RVO 时,按值返回一个含动态资源的对象(如 std::vector、自定义大对象)可能经历:
立即学习“C++免费学习笔记(深入)”;
- 局部对象构造(分配内存、初始化数据)
- 拷贝构造(深拷贝全部内容)
- 局部对象析构(释放其内部资源)
- 返回值对象析构(再次释放)
而启用 RVO 后,整个过程简化为:仅一次构造,无拷贝、无额外析构。这对高频调用的工厂函数、运算符重载(如 operator+)、容器操作等场景,能显著减少 CPU 和内存开销。
如何写出利于 RVO 的代码
你不能“强制开启 RVO”,但可以避免破坏它的常见写法:
- 尽量让函数只有一个 return 语句,且返回同一个具名对象(利于 NRVO)
- 避免在返回前对返回变量做不必要的赋值或交换(例如
obj = other; return obj;可能干扰 NRVO) - 优先返回临时对象字面量(如
return Data{x, y};),C++17 下这类 RVO 是强制的 - 不要为了“避免拷贝”而改用指针或引用返回局部对象——这会导致悬垂指针或内存泄漏,反而更危险
- 配合移动语义:即使 RVO 失效,有移动构造函数也能兜底,比拷贝快得多
现代编译器(GCC、Clang、MSVC)默认开启 RVO/NRVO,无需额外选项。你可以通过观察构造/析构函数调用次数,或查看汇编输出验证是否生效。本质上,RVO 是编译器帮你做的“隐形减负”,重点在于写清楚意图,而不是操心底层搬运。











