Copy semantics elision and move not working as expected
I made a program to evaluate the performance differences between this:
func3(func2(func1()));
vs this:
retval1 = func1(); retval2 = func2(retval1); func3(retval2);
I prefer the latter for readability and ease of debugging, and I wanted to know if the compiler (MSVC 12.0) would optimize intermediate objects in the release build. My test program is like this:
#include <iostream>
using namespace std;
struct Indicator {
Indicator() {cout << "Default constructor" << endl;}
Indicator(const Indicator& other) {cout << "Copy constructor" << endl;}
const Indicator& operator=(const Indicator& other) {cout << "Assignment operator" << endl;}
~Indicator() {cout << "Destructor" << endl;}
};
Indicator func1()
{return Indicator();}
Indicator func2(Indicator&& i)
{return std::move(i);}
Indicator func3(Indicator&& i)
{return std::move(i);}
int main() {
Indicator i = func3(func2(func1()));
cout << &i << endl;
return 0;
}
I was surprised to see that even with -O2, three more instances are created Indicator
:
Default constructor
Copy constructor
Copy constructor
Destructor
Destructor
00000000002EFC70
Destructor
Press <RETURN> to close this window...
This goes against my understanding of move semantics, which is that only one instance is created in this case Indicator
. I also thought that the compiler should be able to use NRVO for chaining function calls. Can someone explain to me what is going on here?
source to share
As per rule 5 , when you defined your copy constructor and copy assignment operator, you disabled the compiler-generated move constructor and moved the assignment operator.
If you define your move constructor, you get the expected result.
Indicator(Indicator&& other) {cout << "Move constructor" << endl;}
Indicator& operator=(Indicator&& other) {cout << "Move assignment operator" << endl;}
source to share