Reputation: 121
For example i have code such as below
//g++ 5.4.0
#include <iostream>
struct data
{
int n;
data()
{
std::cout << "data()\n";
}
data(const data&)
{
std::cout << "data(const data&)\n";
}
data(data&&)
{
std::cout << "data(data&&)\n";
}
};
class container
{
data d;
public:
data getData()
{
return std::move(d);
}
};
int main()
{
container c;
data result = c.getData();
}
And output is:
data()
data(data&&)
I don't understand how it works. I have not declared return type as data&&
, but move constructor works fine for result. Yes, code is std::move(d)
but return type is not data&&
. So, how does it work?
Upvotes: 2
Views: 92
Reputation: 275350
This answer changes in c++17.
data getData()
{
return std::move(d);
}
This method moves d
into its return value.
data x = foo.getData();
this one constructs x
from the return value of getData
. However the C++ standard encourages and permits this construction to be elided if getData
returns a prvalue (a value type that matches). Elision means that the identity and lifetime of the return value and x
are merged. Only one object exists, not two.
This permits skipping side effects, like print statements in move constructors.
So d
is the object moved from, and that move directly constructs x
.
If you change getData
to return data&&
, now no move is done withingetData
but one is done outside when you construct x
.
In c++17 the return value of getData
is never an object, it is a prvalue, and prvalues in c++17 are more like instructions to create objects. In effect elision is no longer optional.
Upvotes: 4
Reputation: 470
If the return type is set to data
(as in your case), then the returned object is a prvalue.
If the return type is set to data&&
, then the returned object is an xrvalue.
In either case, the returned object is an rvalue, and result
's move constructor will be called.
See also: http://stackoverflow.com/a/10159163/4509057
Upvotes: 3