C++返回值优化(RVO)
C++返回值优化(RVO)是编译器直接在调用者内存构造返回对象,避免拷贝或移动,提高性能的优化技术。
C++返回值优化(RVO)
C++ 返回值优化(RVO)
当函数返回一个对象时,按照传统理解,编译器会:
- 在函数内部创建一个临时对象(返回值对象)。
- 通过拷贝构造函数或移动构造函数,将临时对象拷贝或移动到调用者的变量。
这可能导致一次或多次额外的对象构造、拷贝、移动,影响性能。
返回值优化(RVO,Return Value Optimization)就是编译器的一个优化技术,目的是:直接在调用者提供的存储空间中构造返回对象,省去临时对象的创建和拷贝/移动,从而提升性能。
示例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class MyClass {
public:
MyClass() { std::cout << "Constructed\n"; }
MyClass(const MyClass&) { std::cout << "Copy Constructed\n"; }
MyClass(MyClass&&) noexcept { std::cout << "Move Constructed\n"; }
};
MyClass create() {
MyClass obj;
return obj;
}
int main() {
MyClass a = create();
}
- 没有 RVO:
create()
内部先构造obj
- 返回时调用拷贝构造(或移动构造)将
obj
拷贝/移动给a
- 有 RVO:
- 编译器直接在
a
的内存空间中构造obj
- 没有额外的拷贝或移动构造调用
- 编译器直接在
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
MyClass f1() {
MyClass a;
return a; // NRVO 可能生效
}
MyClass f2() {
return MyClass(); // 无名临时对象,RVO 通常生效
}
MyClass f3() {
MyClass a;
MyClass b;
if (some_condition) {
return a; // NRVO 可能生效
} else {
return b; // NRVO 可能无法生效,依赖编译器
}
}
- 其中
f3
中因为有多个返回变量,NRVO 可能失效,编译器会退回使用移动构造。
RVO 的两种主要形式
- NRVO(Named Return Value Optimization) 函数返回的是一个具名变量,比如上面例子中的
obj
,编译器可以直接在调用者提供的空间构造obj
。 - Unnamed RVO 返回的是一个临时对象,比如
return MyClass();
,编译器也可以直接在调用者空间构造该临时对象。
C++ 标准对 RVO 的支持
- C++03:RVO 是一种允许的优化,但不是必须,编译器可选实现。
- C++11:引入了移动语义,减少了拷贝开销,但 RVO 依然是编译器优化。
- C++17:对某些情形下的返回值,标准强制执行所谓的拷贝省略,即 RVO 成为必需。
简言之,C++17 以后部分情况下编译器必须进行返回值优化,禁止调用拷贝或移动构造。
本文由作者按照 CC BY 4.0 进行授权