Search code examples
c++rvo

Why does not apply RVO in this code


There is a Complex class with constructor which prints a message for RVO.
I have tested Complex's operator+ method in gtest.
If RVO is occurred, prints "Complex!!" messages for 3 times.
But There are "Complex!!" messages for 5 times.
RVO is not occurred, I think.
I have compiled this code by c++98 and c++11
Why does not occur 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;
    }
}

Solution

  • RVO isn't an optimization to prevent objects from being constructed - it's an optimization to avoid unnecessary extra copies or moves.

    Your example is constructing three objects (a, b, and c) and then constructing two more (a+b twice in the loop). Those objects all must be constructed, there's no way to optimize around that - the compiler can't break apart the Complex() temporary initialization within operator+ and unpack it into the assignments to real and imag within operator=.

    If you'd instrumented your copy and move constructor, you'd see that they were not called in your example. But they could have been. The temporary created within operator+() is conceptually moved into the return of the function before being bound to the reference in Complex::operator=(). It's that move that's elided via RVO, and it's that move that you would see if you compiled with -fno-elide-constructors.