Consider the following function:
Widget f(Widget w) {
return w;
}
Supposing that Widget
implements both copy and move constructors, according to the C++ standard, w
has to be treated as a rvalue object in the return statement, in case the compiler would not consider copy elision a better alternative.
On the other hand, consider the version below:
Widget f(Widget&& w) {
return w;
}
As opposite to the first version, according to Item 25
of Effective Modern C++
, the author seems to be implying that returning w
would certainly invoke the copy constructor. In other words, he suggests to return std::move(w)
instead, in order to make the compiler use the (possibly faster) move constructor.
Can you explain why the second version of f()
taking a Widget&&
as argument is not equivalent to the first version taking a Widget
by value with respect to the constructor being called in the return statement, also considering that in the body of both the functions the expression w
refers to an lvalue
?
Complete example demonstrating the behavior:
#include <iostream>
struct Widget
{
Widget() { std::cout << "constructed" << std::endl; }
~Widget() { std::cout << "destructed" << std::endl; }
Widget(const Widget&) { std::cout << "copy-constructed" << std::endl; }
Widget(Widget&&) { std::cout << "move-constructed" << std::endl; }
};
Widget
f1(Widget w)
{
return w;
}
Widget
f2(Widget&& w)
{
return w;
}
int
main()
{
f1(Widget {});
std::cout << std::endl;
f2(Widget {});
}
Output:
constructed
move-constructed
destructed
destructed
constructed
copy-constructed
destructed
destructed