See the below example of returning an optional of UserName
- a movable/copyable class.
std::optional<UserName> CreateUser()
{
UserName u;
return {u}; // this one will cause a copy of UserName
return u; // this one moves UserName
}
int main()
{
auto d = CreateUser();
}
Why does return {u}
cause a copy and return u
a move?
Here's the related coliru sample: http://coliru.stacked-crooked.com/a/6bf853750b38d110
Another case (thanks to the comment from @Slava):
std::unique_ptr<int> foo()
{
std::unique_ptr<int> p;
return {p}; // uses copy of unique_ptr and so it breaks...
}
Because returning a name of an object with automatic storage duration is treated as returning an rvalue of the object. Note this works only if the expression in the return statement is a (possibly parenthesized, not including braces) name, like return u;
or return (u);
, so return {u};
works as usual, i.e. the copy constructor is invoked.
Related part in the standard [class.copy.elision]/3:
In the following copy-initialization contexts, a move operation might be used instead of a copy operation:
- If the expression in a return statement ([stmt.return]) is a (possibly parenthesized) id-expression that names an object with automatic storage duration declared in the body or parameter-declaration-clause of the innermost enclosing function or lambda-expression, or
- ...
overload resolution to select the constructor for the copy is first performed as if the object were designated by an rvalue.