Basically, what I am doing is as follows. My class D has three constructors (default, move, copy) and two overloaded assignment operators (move and copy). I expected that any creation of a D type object will invoke at least one of the five.
However, creating a D object "d4" as follows does not invoke any of them:
D d4( foo() ); // foo returns a D
Here is the code that reproduces the issue I was wondering about:
#include <iostream>
#include <vector>
#include <cassert>
using std::cout;
using std::endl;
class D {
public:
D()
{ cout << "D default"<<endl;}
D(const D& d)
{
cout << "D copy" << endl;
}
D(D&& d)
{
cout << "D rval" << endl;
assert(0);
}
D& operator=(D&& d)
{
cout << "D mv assign" << endl;
return *this;
}
D& operator=(const D& d)
{
cout << "D copy assign" << endl;
return *this;
}
volatile int v;
};
// return
D foo()
{
D res;
cout <<"returning a non const D" << endl;
return res;
}
int main()
{
D d4(foo());
return 0;
}
Basically, I assumed that, the D(D&& d) will be invoked to create d4 as foo() returns a temporary whose address may not be taken. Actually, that was true only when the return value optimization was disabled by -fno-elide-constructors.
However, if it was not specified, the RV optimization is by default turned on even on -O0. Then, what I have seen is as follows:
D default
returning a non const D
All I saw from the stdout came from foo(). Creation of d4 itself gave me nothing. This is different from what I expected.
I expected the following. A memory space for the returned value is allocated in the caller's stack rather than the callee's stack. The default constructor is called to touch the memory space. No copy will happen from the callee's stack to the caller's stack. Following that, another memory space is allocated in the caller's stack. As the returned value is an rvalue, the move constructor is called to write something on the "another memory space in the caller's stack."
I know that might require redundant memory space. However, particularly in my example, the move constructor will die with assert(0). Whatsoever constructor but it will let the program continue. As a result, the return value optimization made difference in terms of program's output.
Is that expected? If so, what is the reason behind? I have tested both g++-7.3.0 and clang++-5.0.1. They were the same.
Because you use C++17, which promises RVO, even you added -O0. this maybe help