Reputation: 20746
Is it ok that the following code
#include <iostream>
struct Foo
{
Foo() { std::cout << "Foo::Foo" << std::endl; }
~Foo() { std::cout << "Foo::~Foo" << std::endl; }
Foo(const Foo&) { std::cout << "Foo::Foo(const Foo&)" << std::endl; }
Foo& operator=(const Foo&) { std::cout << "Foo::operator=(const Foo&)" << std::endl; return *this; }
Foo(Foo&&) { std::cout << "Foo::Foo(Foo&&)" << std::endl; }
Foo& operator=(Foo&&) { std::cout << "Foo::operator=(Foo&&)" << std::endl; return *this; }
};
Foo foo()
{
Foo second;
return second;
}
int main()
{
foo();
}
produces such output:
Foo::Foo
Foo::Foo(Foo&&)
Foo::~Foo
Foo::~Foo
Why does it call move constructor instead of the copy constructor?
Upvotes: 2
Views: 247
Reputation: 4997
second
is returned from foo
, and, being a local object, is treated as an rvalue (thanks to Nir Friedman for the correct explanation). The returned Foo
object is constructed from a temporary, which binds to the move constructor.
Modern compiler should skip the move constructor call and use copy elision (demo).
Upvotes: 2
Reputation: 17704
The answer is simply because the standard says so. Section 12.8, paragraph 32:
When the criteria for elision of a copy/move operation are met, but not for an exception-declaration, and the object to be copied is designated by an lvalue, or when the expression in a return statement 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, overload resolution to select the constructor for the copy is first performed as if the object were designated by an rvalue.
And that's basically all there is to it. Logically, if the variable has automatic storage duration, and you return
it, then immediately after the return, the variable will not exist any more when the local scope cleans up. That is why, even though it is an lvalue, it is quite similar to an rvalue. Because it's still technically an lvalue, this exception has to be made explicitly in the standard, and here we are. Note that this whole situation is specific to return
ing from a function, and does not include scope ending in general.
Upvotes: 3