为什么不在此代码中应用RVO

Gye*_* Do -1 c++ rvo

有一个带有构造函数的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)

eer*_*ika 7

返回值优化是一种复制省略.简单来说,它是一种避免复制对象的优化.它不会通过其他方式避免创建对象.

您可以通过观察副本和移动构造函数的副作用来验证是否已应用RVO.

您的复制构造函数没有副作用,因此无法观察RVO是否已应用.

当RVO发生时,两个"复杂!!" 不应打印调用operator +的消息.

不会.这些消息打印在类的常规(非复制)构造函数中.RVO对调用常规构造函数的次数没有影响.


Bar*_*rry 7

RVO不是防止构造对象的优化- 它是一种优化,以避免不必要的额外副本或移动.

你的例子是构造三个对象(a,bc),然后再构造两个(a+b循环中两次).所有这些对象都必须构建,没有办法优化 - 编译器不能拆分Complex()临时初始化operator+并将其解压缩到指定内部realimag内部operator=.

如果您已经为自己的副本和移动构造函数进行了检测,那么您会看到它们未在您的示例中调用.但他们本来可以.operator+()在被绑定到引用之前,在概念上将临时创建的内容移动到函数的返回中Complex::operator=().这是是威盛RVO省略的举动,它的这一举动,你会看到,如果你编译-fno-elide-constructors.