有一个带有构造函数的Complex类,它为RVO打印一条消息.
我在gtest中测试了Complex的operator +方法.
如果发生RVO,请打印"Complex !!" 消息3次.
但是有"复杂!!" 消息5次.
我想,RVO没有发生.
我用c ++ 98和c ++ 11编译了这段代码
为什么不发生RVO?
#include <stdio.h>
class Complex {
friend Complex operator+(const Complex&, const Complex&);
public:
Complex(double r = 0.0, double i = 0.0) : real(r), imag(i) { printf("\nComplex!!\n");}
Complex(const Complex& c) : real(c.real), imag(c.imag) {}
Complex& operator=(const Complex& c) {
real = c.real;
imag = c.imag;
return *this;
}
~Complex() {}
private:
double real;
double imag;
};
Complex operator+(const Complex& lhs, const Complex& rhs)
{
return Complex(lhs.real + rhs.real, lhs.imag + rhs.imag);
}
int main()
{
Complex a(1.0), b(2.0), c;
for (int i = 0; i < 2; i++) {
c = a + b;
}
}
Run Code Online (Sandbox Code Playgroud)
返回值优化是一种复制省略.简单来说,它是一种避免复制对象的优化.它不会通过其他方式避免创建对象.
您可以通过观察副本和移动构造函数的副作用来验证是否已应用RVO.
您的复制构造函数没有副作用,因此无法观察RVO是否已应用.
当RVO发生时,两个"复杂!!" 不应打印调用operator +的消息.
不会.这些消息打印在类的常规(非复制)构造函数中.RVO对调用常规构造函数的次数没有影响.
RVO不是防止构造对象的优化- 它是一种优化,以避免不必要的额外副本或移动.
你的例子是构造三个对象(a,b和c),然后再构造两个(a+b循环中两次).所有这些对象都必须构建,没有办法优化 - 编译器不能拆分Complex()临时初始化operator+并将其解压缩到指定内部real和imag内部operator=.
如果您已经为自己的副本和移动构造函数进行了检测,那么您会看到它们未在您的示例中调用.但他们本来可以.operator+()在被绑定到引用之前,在概念上将临时创建的内容移动到函数的返回中Complex::operator=().这是这是威盛RVO省略的举动,它的这一举动,你会看到,如果你编译-fno-elide-constructors.