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

时间:2016-07-14 14:11:39

标签: c++ rvo

有一个带有构造函数的Complex类,它为RVO打印一条消息 我在gtest中测试过Complex的运算符+方法 如果发生了RVO,请打印"复杂!!"消息3次。
但是有#34;复杂!!"消息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;
    }
}

2 个答案:

答案 0 :(得分:7)

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

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

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

  

当发生RVO时,两个&#34;复杂!!&#34;不应打印调用operator +的消息。

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

答案 1 :(得分:7)

RVO不是防止对象构造的优化 - 它是一种优化,可以避免不必要的额外复制或移动。

您的示例是构建三个对象(abc),然后在循环中构建两个(a+b两次)。所有必须构造的对象,没有办法优化 - 编译器不能拆分Complex()中的operator+临时初始化并将其解压缩到赋值中real内的imagoperator=

如果您已经为自己的副本和移动构造函数进行了检测,那么您会看到它们未在您的示例中调用。但他们本来可以。在operator+()中创建的临时值在被绑定到Complex::operator=()中的引用之前在概念上被移动到函数的返回中。