返回值优化
維基百科,自由的 encyclopedia
返回值优化(Return value optimization,缩写为RVO)是C++的一项编译优化技术。即删除保持函数返回值的临时对象。这可能会省略两次复制构造函数,即使复制构造函数有副作用。[1] [2]
典型地,当一个函数返回一个对象实例,一个临时对象将被创建并通过复制构造函数把目标对象复制给这个临时对象。C++标准允许省略这些复制构造函数,即使这导致程序的不同行为,即使编译器把两个对象视作同一个具有副作用。 [3]
#include <iostream>
struct C {
C() {}
C(const C&) { std::cout << "A copy was made.\n"; }
};
C f() {
return C();
}
int main() {
std::cout << "Hello World!\n";
C obj = f();
}
对于函数返回类对象,一种实现办法是在函数调用语句前在stack frame上声明一个隐藏对象,把该对象的地址隐蔽传入被调用函数,函数的返回对象直接构造或者复制构造到该地址上。[4]例如:
struct Data {
char bytes[16];
};
Data f() {
Data result = {};
// generate result
return result;
}
int main() {
Data d = f();
}
可能产生的代码如下:
struct Data {
char bytes[16];
};
Data * f(Data * _hiddenAddress) {
Data result = {};
// copy result into hidden object
*_hiddenAddress = result;
return _hiddenAddress;
}
int main() {
Data _hidden; // create hidden object
Data d = *f(&_hidden); // copy the result into d
}
这引起了Data
对象被复制两次。
另一种技术是命名返回值优化(Named return value optimization,NRVO)。[5]NRVO去除了基于栈的返回值的构造与析构。虽然这会导致优化与未优化的程序的不同行为。
struct Data {
char bytes[16];
};
void f(Data *p) {
// generate result directly in *p
}
int main() {
Data d;
f(&d);
}
大部分C++编译器均支持返回值优化。[1][6][7]在某些环境下,编译器不能执行此优化。一个常见情形是当函数依据执行路径返回不同的命名对象,或者命名对象在asm内联块中被使用:[4][6][8]
#include <iostream>
struct C {
C(int j) { i = j; }
C(const C&) { std::cout << "A copy was made.\n"; }
int i;
};
C f(bool cond = false) {
C first(101);
C second(102);
// the function may return one of two named objects
// depending on its argument. RVO might not be applied
return cond ? first : second;
}
int main() {
std::cout << "Hello World!\n";
C obj = f(true);
}