一文搞懂c++中rvo返回值优化如何使用
一个例子搞懂返回值优化¶
现代C++编译器(C++11及以上)会进行返回值优化(Return Value Optimization, RVO)和命名返回值优化(Named Return Value Optimization, NRVO)。
其作用是避免创建临时对象,避免拷贝/赋值构造函数的调用,从而提升性能。
#include <iostream>
class BigObj {
public:
BigObj() {
printf("construction …\n");
}
BigObj(const BigObj& s) {
printf("Expensive copy …\n");
}
BigObj& operator=(const BigObj& s) {
printf("Expensive assignment …\n");
return *this;
}
~BigObj() {
printf("destruction …\n");
}
static BigObj BigObjFactory() {
BigObj local;
return local;
}
// 不同分支返回的是同一个对象,编译器可以优化。
static BigObj BranchFactorySameObj(bool flag) {
BigObj a;
if (flag) return a;
else return a;
}
};
BigObj::BigObjFactory()函数返回一个局部对象local,而main()函数中直接使用这个返回值来构造obj。编译器会优化这个过程,直接将local构造在obj的内存位置上,避免了复制构造函数的调用。
int main(){
// 返回值优化
BigObj obj = BigObj::BigObjFactory();
// construction …
// destruction …
// 分支返回值优化
BigObj obj = BigObj::BranchFactorySameObj(true);
// construction …
// destruction …
return 0;
}
正如上一篇[一文搞懂c++move函数的使用]中提到,由于返回值优化的存在,返回值不需要使用std::move。
编译器已优化返回值的场景(RVO)不用std::move。
// 不好的用法
static BigObj BigObjFactory() {
BigObj local;
return std::move(local);
}
无法进行rvo优化的情况¶
- 赋值已经存在的对象
当返回的对象用于赋值给已存在的对象时(而非直接初始化新对象),编译器会调用赋值运算符而非拷贝构造函数,此时优化不会触发。
// 没有返回值优化 BigObj obj; obj = BigObj::BigObjFactory(); // 无法优化的情况,打印: // construction … // construction … // Expensive assignment … // destruction … // destruction …
- 多分支返回不同对象
若函数存在多个返回路径(如if-else分支),且返回不同的命名对象,编译器可能无法确定优化目标而放弃优化。
static BigObj BranchFactory(bool flag) {
BigObj a, b;
if (flag) return a; // 无法优化
else return b; // 无法优化
}
// 无法优化的情况,打印:
// BigObj obj = BigObj::BranchFactory(true);
// construction …
// construction …
// Expensive copy …
// destruction …
// destruction …
// destruction …