什么是 RVO?
RVO(Return Value Optimization,返回值优化)是 C++ 编译器的一种优化技术,通过消除不必要的临时对象拷贝来提升性能。NRVO(Named RVO)是 RVO 的变体,针对已命名的局部变量。
关键时间点:
- C++11 之前:RVO/NRVO 作为编译器优化选项存在
- C++17:强制要求对 prvalue(纯右值)执行 RVO
- C++20:进一步扩展了强制 RVO 的场景
先来看一张图直观理解:

代码示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
| #include <iostream> #include <string> #include <utility>
class BigObject { public: BigObject() { std::cout << "Constructor\n"; } ~BigObject() { std::cout << "Destructor\n"; } BigObject(BigObject const&) { std::cout << "Copy Constructor\n"; } BigObject& operator=(BigObject const&) { std::cout << "Assignment Operator\n"; return *this; } BigObject(BigObject&&) { std::cout << "Move Constructor\n"; } };
BigObject f1() { return BigObject(); }
BigObject f2() { BigObject obj; return obj; }
BigObject f3() { BigObject obj[1]; return obj[0]; }
BigObject f4() { return std::move(BigObject()); }
BigObject f5() { BigObject obj; return const_cast<BigObject&>(obj); }
int main() { std::cout << "1 ------------------------" << std::endl; { BigObject obj1 = f1(); } std::cout << "2 ------------------------" << std::endl; { BigObject obj2 = f2(); } std::cout << "3 ------------------------" << std::endl; { BigObject obj3 = f3(); } std::cout << "4 ------------------------" << std::endl; { BigObject obj4 = f4(); } std::cout << "5 ------------------------" << std::endl; { BigObject obj5 = f5(); }
return 0; }
|
运行结果
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| 1 ------------------------ Constructor Destructor 2 ------------------------ Constructor Destructor 3 ------------------------ Constructor Copy Constructor Destructor Destructor 4 ------------------------ Constructor Move Constructor Destructor Destructor 5 ------------------------ Constructor Copy Constructor Destructor Destructor
|
结果分析
| 函数 | 输出 | RVO 状态 | 原因 |
|---|
f1() | Constructor + Destructor | ✅ RVO 生效 | 返回纯右值(prvalue),C++17 强制优化 |
f2() | Constructor + Destructor | ✅ NRVO 生效 | 返回命名局部对象,编译器优化消除拷贝 |
f3() | 多了 Copy Constructor | ❌ 无 RVO | 返回数组元素,编译器无法确定对象来源 |
f4() | 多了 Move Constructor | ❌ 无 RVO | std::move 将对象转为 xvalue,阻止 RVO |
f5() | 多了 Copy Constructor | ❌ 无 RVO | const_cast 破坏了 RVO 的前提条件 |
RVO 的触发条件
必须满足的条件
- 返回类型匹配:返回的对象类型必须与函数返回类型完全一致
- 返回局部对象:对象必须是函数内的自动存储期变量
- 不能是静态变量:静态变量的生命周期超出函数作用域
- 不能有多个返回路径返回不同对象:所有 return 语句应返回同一个对象
会阻止 RVO 的操作
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| BigObject bad1() { BigObject obj; return std::move(obj); }
BigObject bad2(BigObject obj) { return obj; }
BigObject global; BigObject bad3() { return global; }
BigObject bad4(bool cond) { BigObject a, b; return cond ? a : b; }
|
最佳实践
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| BigObject good1() { BigObject obj; return obj; }
BigObject good2() { return BigObject(); }
BigObject createObject(int type) { if (type == 1) { return BigObject(); } return BigObject(); }
|
核心建议
- 永远不要对返回值使用
std::move:这会阻止 NRVO,反而降低性能 - 信任编译器:现代编译器(GCC、Clang、MSVC)都能很好地执行 RVO/NRVO
- 理解 C++17 的变化:prvalue 的返回现在是强制优化的,不再依赖编译器
- 保持代码简洁:简单的返回语句更容易被优化