-1

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;
    }
}
Cheers and hth. - Alf
  • 142,714
  • 15
  • 209
  • 331
appchemist
  • 345
  • 2
  • 3
  • 11
  • 6
    There are 5 constructor calls: one each to initialize `a`, `b` and `c`, and one for each invocation of `operator+`. Why do you think there would be any other number? Which ones do you think shouldn't happen? – user253751 Jul 14 '16 at 14:12
  • 3
    RVO elides calls to copy constructors and move constructors, not others. So your code does not tell you anything about RVO. – Cheers and hth. - Alf Jul 14 '16 at 14:16
  • 1
    It could occur for `Complex c = a + b;`. Now you just have an assignment, which is not applicable. – Bo Persson Jul 14 '16 at 14:17
  • When RVO is occurred, two "Complex!!" messages in invocation of operator+ should not be printed. But it is printed. – appchemist Jul 14 '16 at 14:18
  • 4
    @GyeongWonDo: That's wrong. You're misunderstanding what elision is doing. – Nicol Bolas Jul 14 '16 at 14:18

2 Answers2

7

Return value optimization is a form of copy elision. In simpler terms, it is an optimization that avoids copying objects. It does not avoid creation of objects by other means.

You can verify whether RVO has been applied by observing the side effects of the copy and the move constructor.

Your copy constructor has no side effects, so it impossible to observe whether RVO has or hasn't been applied.

When RVO is occurred, two "Complex!!" messages in invocation of operator+ should not be printed.

No. Those messages are printed in the regular (not copy-) constructor of the class. RVO does not have an effect on how many times a regular constructor is called.

eerorika
  • 232,697
  • 12
  • 197
  • 326
  • Thank you, I write print some messages(side effects) in copy constructor. And I checked copy constructor is called or not called using -fno-elide-constructors option – appchemist Jul 14 '16 at 14:55
7

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.

Barry
  • 286,269
  • 29
  • 621
  • 977
  • I want to remove the temporary created within operator+(). In this case, How can i remove this temporary using RVO? – appchemist Jul 14 '16 at 14:39
  • @GyeongWonDo It's not something you have to *do*. If you wrote `Complex d = a + b;`, that wouldn't perform a copy/move - it would construct the temporary in-place in `d`. But `operator+()` has to construct an object. – Barry Jul 14 '16 at 14:45
  • I have checked that copy constructor is called with -fno-elide-constructors option. But Copy constructor is not called without -fno-elide-constructors options. You mean that this is RVO? – appchemist Jul 14 '16 at 14:53
  • I have one more question. Where can i read about RVO? Specifically When can be occured RVO? – appchemist Jul 14 '16 at 14:57
  • @GyeongWonDo Yes, that copy/move was elided. – Barry Jul 14 '16 at 15:03
  • @GyeongWon Do You can read about copy elision here: http://en.cppreference.com/w/cpp/language/copy_elision as well as in the standard http://open-std.org/JTC1/SC22/WG21/docs/papers/2016/n4594.pdf (search for "copy elision"). – Jesper Juhl Jul 14 '16 at 15:13
  • i read "efficient c++" book's chapter 4. this book says that the temporary created within operator +(). is this incorrect or do i misunderstand? – appchemist Jul 14 '16 at 15:15
  • Just because some object's `operator+()` creates a temporary doesn't mean that every class's `operator+()` creates a temporary. – Sam Varshavchik Jul 14 '16 at 17:42