'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;
}
- Instruction
rectangle r1will call Constructor which is ok. - Instruction
rectangle r2 = r1will call Copy Constructor which still is understandable. - Instruction
r1 + r2, first call Constructor because ofrectangle tempthen calls Copy Constructor. so it is not a problem too. - 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
r3with returned value but this call is not executed, why?
- Constructor because of
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:
- Default constructor will be called/used for the statement
rectangle temp;inside the overloadedoperator+. So you will get the outputConstructor. - Copy constructor will be called due to the return statement
return temp;for which you will get the outputCopy constructor. Thus, a nameless temporary is returned to the caller. - 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 |
