As already mentioned in comments to the first answer, the return std::move(...);
construct can make a difference in cases other than returning of local variables. Here's a runnable example that documents what happens when you return a member object with and without std::move()
:
#include <iostream>
#include <utility>
struct A {
A() = default;
A(const A&) { std::cout << "A copied\n"; }
A(A&&) { std::cout << "A moved\n"; }
};
class B {
A a;
public:
operator A() const & { std::cout << "B C-value: "; return a; }
operator A() & { std::cout << "B L-value: "; return a; }
operator A() && { std::cout << "B R-value: "; return a; }
};
class C {
A a;
public:
operator A() const & { std::cout << "C C-value: "; return std::move(a); }
operator A() & { std::cout << "C L-value: "; return std::move(a); }
operator A() && { std::cout << "C R-value: "; return std::move(a); }
};
int main() {
// Non-constant L-values
B b;
C c;
A{b}; // B L-value: A copied
A{c}; // C L-value: A moved
// R-values
A{B{}}; // B R-value: A copied
A{C{}}; // C R-value: A moved
// Constant L-values
const B bc;
const C cc;
A{bc}; // B C-value: A copied
A{cc}; // C C-value: A copied
return 0;
}
Presumably, return std::move(some_member);
only makes sense if you actually want to move the particular class member, e.g. in a case where class C
represents short-lived adapter objects with the sole purpose of creating instances of struct A
.
Notice how struct A
always gets copied out of class B
, even when the class B
object is an R-value. This is because the compiler has no way to tell that class B
's instance of struct A
won't be used any more. In class C
, the compiler does have this information from std::move()
, which is why struct A
gets moved, unless the instance of class C
is constant.