-
编译器可能会创建临时对象,然后利用复制构造函数将其复制给返回值。这种情况下多消耗了构造函数与析构函数的时间。
因此针对一些情况,编译器可能会进行RVO
以下为两个案例:
a. (Complex 是复数的类)
Complex operator+ (const Complex &a, const Complex &b) {
Complex retVal;
retVal.real = a.real + b.real;
retVal.imag = a.imag + b.imag;
return retVal;
}
更简洁的写为
Complex operator+ (const Complex &a, const Complex &b) {
Complex retVal(a.real + b.real, a.imag + b.imag);
return retVal;
}
编译器不对该版本进行RVOb.
Complex operator+ (const Complex &a, const Complex &b) {
double r = a.real + b.real;
double i = a.imag + b.imag;
return Complex(r,i); //return Complex(a.real + b.real, a.imag + b.imag);
}编译器会对b进行RVO(即必须定义拷贝构造函数来“开启”RVO,如果没有拷贝构造函数也就不存在RVO了。Complex(r,i)就是拷贝构造函数)
计算性构造函数
当编译器无法执行RVO时,可按计算性构造函数的形式来实现
如构造函数写为
Complex::Complex (const Complex &a, const Complex &b)
:real(a.real + b.real), imag(a.imag + b.imag){
}
则原来的重载操作符+可写为
Complex operator+ (const Complex &a, Complex &b){
return Complex(a, b);
}
3.总结:
a. 如果必须按值返回对象,通过RVO可以省去创建和销毁局部对象的步骤,改善性能
b. RVO的应用要遵照编译器的实现而定,这需要参考编译器文档或者通过实验来判断是否使用RVO以及何时使用
c. 通过编写计算性构造函数可以更好的使用RVO。