No. The best practice is directly return t;
.
In case class T
has move constructor not deleted, and notice t
is a local variable that return t
is eligible for copy elision, it move constructs the returned object just like return std::move(t);
does. However return t;
is still eligible to copy/move elision, so the construction may be omitted, while return std::move(t)
always constructs the return value using move constructor.
In case move constructor in class T
is deleted but copy constructor available, return std::move(t);
will not compile, while return t;
still compiles using copy constructor. Unlike @Kerrek mentioned, t
is not bound to an rvalue reference. There's a two-stage overload resolution for return values that eligible for copy elision -- try move first, then copy, and both move and copy is possibly elided.
class T
{
public:
T () = default;
T (T&& t) = delete;
T (const T& t) = default;
};
T foo()
{
T t;
return t; // OK: copied, possibly elided
return std::move(t); // error: move constructor deleted
return static_cast<T&>(t); // OK: copied, never elided
}
If the return
expression is lvalue and not eligible for copy elision (most likely you are returning a non-local variable or lvalue expression) and you still would like to avoid copy, std::move
will be useful. But keep in mind that the best practice is make copy elision possible to happen.
class T
{
public:
T () = default;
T (T&& t) = default;
T (const T& t) = default;
};
T bar(bool k)
{
T a, b;
return k ? a : b; // lvalue expression, copied
return std::move(k ? a : b); // moved
if (k)
return a; // moved, and possibly elided
else
return b; // moved, and possibly elided
}
12.8(32) in the standard describes the process.
12.8 [class.copy]
32 When the criteria for elision of a copy operation are met or would be met save for the fact that the source object is a function parameter, and the object to be copied is designated by an lvalue, overload resolution to select the constructor for the copy is first performed as if the object were designated by an rvalue. If overload resolution fails, or if the type of the first parameter of the selected constructor is not an rvalue reference to the object’s type (possibly cv-qualified), overload resolution is performed again, considering the object as an lvalue. [ Note: This two-stage overload resolution must be performed regardless of whether copy elision will occur. It determines the constructor to be called if elision is not performed, and the selected constructor must be accessible even if the call is elided. —end note ]