[C++] 返回值优化

什么是返回值优化?

返回值优化(Return Value Optimization, RVO)是C++编译器的一种优化技术,用于减少不必要的对象拷贝,特别是在函数返回临时对象的场景中。RVO 可以显著提高程序性能,并减少临时对象的生成和析构操作。

在C++中,函数返回值通常会涉及临时对象的创建和销毁。例如,当函数返回一个对象时,通常会创建一个临时对象来存储返回值,然后将其拷贝到接收返回值的变量中。返回值优化(RVO)是编译器的一种优化技术,它避免了这些临时对象的拷贝操作。

RVO的工作机制

通常情况下,返回一个对象的过程涉及两步:

  1. 创建并初始化一个临时对象(可能是函数内的局部对象)。
  2. 将这个临时对象拷贝或移动到调用者提供的目标位置。

RVO通过直接在目标位置构造返回的对象,跳过了临时对象的创建,从而避免了拷贝或移动操作。

例子(无RVO vs. 有RVO)

没有RVO时:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class MyClass {
public:
MyClass() { std::cout << "Constructor" << std::endl; }
MyClass(const MyClass&) { std::cout << "Copy Constructor" << std::endl; }
~MyClass() { std::cout << "Destructor" << std::endl; }
};

MyClass createObject() {
MyClass obj;
return obj; // 返回局部对象,会调用拷贝构造函数
}

int main() {
MyClass newObj = createObject(); // 接收返回值,会再次拷贝
}

在上述代码中,createObject()函数返回一个局部对象 obj,在没有RVO的情况下:

  1. 首先构造局部对象 obj
  2. 然后调用拷贝构造函数将 obj拷贝到一个临时对象(用来保存返回值)。
  3. 最后将这个临时对象拷贝到 newObj中。

因此,会涉及两次拷贝构造调用,这样的拷贝是性能上的浪费。

有RVO时:

1
2
3
4
5
6
7
8
MyClass createObject() {
MyClass obj;
return obj; // RVO优化,直接在返回位置构造
}

int main() {
MyClass newObj = createObject(); // 直接在newObj上构造对象,无需拷贝
}

在启用RVO的情况下,编译器会跳过临时对象的创建,直接在 newObj的内存位置上构造 obj,避免了不必要的拷贝操作。

RVO的类型

  1. 命名返回值优化(Named Return Value Optimization, NRVO):NRVO是RVO的一种形式,发生在返回值是命名的局部变量时。例如,函数返回一个命名的局部对象,编译器会直接在调用者的内存空间中构造该对象,而不是先创建一个临时对象。
  2. 标准RVO:标准RVO发生在返回一个未命名的临时对象时。例如,函数返回一个临时构造的对象,而不是局部变量。这种优化在C++17后是强制执行的,不再依赖于编译器是否选择进行优化。

C++17 中的强制RVO

从C++17开始,标准RVO成为强制行为,编译器必须执行返回值优化,不再需要拷贝或移动临时对象。例如:

1
2
3
MyClass createObject() {
return MyClass(); // C++17中,直接在返回位置构造对象
}

在C++17之前,编译器可能会选择不进行优化,但从C++17开始,编译器必须直接在目标位置构造返回的对象,从而完全消除了临时对象和拷贝构造的开销。

总结

  • RVO(返回值优化)是一种编译器优化技术,可以在函数返回对象时避免不必要的临时对象拷贝。
  • NRVO(命名返回值优化)是RVO的一种形式,应用于返回命名的局部变量。
  • C++17中强制执行了RVO,编译器必须优化返回临时对象的场景,进一步提高了程序效率。

[C++] 返回值优化
https://erlsrnby04.github.io/2024/09/22/C-返回值优化/
作者
ErlsrnBy04
发布于
2024年9月22日
许可协议