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?

+3


source to share


1 answer


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;}

      

Working demo

+6


source







All Articles