'Copy Constructor is not called when storing result of overloaded operator+

I'm trying to figure out the ways when copy constructor is called in c++ but due to compiler optimizations it's really hard for me to figure it out.

Here is the code which I'm trying to figure it out:

#include <iostream>
using namespace std;


class rectangle
{
public:
   rectangle()
   {
      cout << "Constructor" << endl;
   };
   rectangle(const rectangle& copied){
      cout << "Copy constructor" << endl;
   };
   rectangle operator+(const rectangle& r){
      rectangle temp;
      return temp;
   }
   ~rectangle()
   {
      cout << "Destructor" << endl;
   };
};


int main () {
   rectangle r1;              //constructor
   rectangle r2 = r1;         //copy constructor
   r1 + r2;                    //copy constructor

   //Now let's combine two last one to get two copy constructor:
   rectangle r3 = r1 + r2;    //just one copy constructor;
   return 0;
}
  1. Instruction rectangle r1 will call Constructor which is ok.
  2. Instruction rectangle r2 = r1 will call Copy Constructor which still is understandable.
  3. Instruction r1 + r2, first call Constructor because of rectangle temp then calls Copy Constructor. so it is not a problem too.
  4. The problem is here in rectangle r3 = r1 + r2; instruction : My expectation is to have following calls:
    • Constructor because of rectangle temp.
    • Copy Constructor because of returning the value of + operator.
    • Copy Constructor to initialize the r3 with returned value but this call is not executed, why?

Note: to disable the returning optimization of compiler I'm using -fno-elide-constructors flag.

Current Behavior:

$ g++ test.cpp -fno-elide-constructor
$ ./a.out
Constructor
Copy constructor
Constructor
Copy constructor
Destructor
Destructor
Constructor
Copy constructor
Destructor
Destructor
Destructor
Destructor

Expected Behavior:

$ ./a.our
Constructor
Copy constructor
Constructor
Copy constructor
Destructor
Destructor
Constructor
Copy constructor
Copy constructor
Destructor
Destructor
Destructor
Destructor
Destructor


Solution 1:[1]

This is due to return value optimization aka RVO which is mandatory from C++17.

From mandatory copy elison documentation:

Under the following circumstances, the compilers are required to omit the copy and move construction of class objects, even if the copy/move constructor and the destructor have observable side-effects. The objects are constructed directly into the storage where they would otherwise be copied/moved to. The copy/move constructors need not be present or accessible:

In the initialization of an object, when the initializer expression is a prvalue of the same class type (ignoring cv-qualification) as the variable type...

Now lets apply this to your case. When you wrote

rectangle r3 = r1 + r2;

The above statement has the following effects in C++17:

  1. Default constructor will be called/used for the statement rectangle temp; inside the overloaded operator+. So you will get the output Constructor.
  2. Copy constructor will be called due to the return statement return temp; for which you will get the output Copy constructor. Thus, a nameless temporary is returned to the caller.
  3. Now, since the nameless temporary returned in the last step is a prvalue and RVO is mandatory from C++17(and so the compiler flag has no effect on RVO), using the above quoted statement that nameless temporary prvalue will be directly used to initialize the object r3.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1