I am writing library which wraps a lot of functions and methods from other library. To avoid coping of return values I am applying std::forward
like so:
template<class T>
T&& wrapper(T&& t) {
f(t); // t passed as lvalue
return std::forward<T>(t);
}
f
returns void
and takes T&&
(or overloaded on valueness). Wrapper always returns wrappers's param and on returned value should preserve valuness of argument. Do I actually need to use std::forward
in return
? Does RVO makes it superfluous? Does the fact that it is a reference (R or L) makes it superfluous? Is it needed if return is not last function statement (inside some if)?
It is debatable if wrapper()
should return void
or T&&
, because caller have access to evaluated value via arg (which is reference, R or L). But in my case I need to return value so that wrapper()
can be used in expressions.
It might be irrelevant to the question, but it is known that functions f
does not steal from t
, so 1st use of std::forward
in f(std::forward<T>(t))
is superfluous and it was removed by me.
I've wrote small test: https://gist.github.com/3910503
Test shows, that returning unforwarded T
- does creates extra copy in gcc48 and clang32 with -O3 (RVO does not kicks in).
Also, I was not able to get bad behavior from UB in:
auto&& tmp = wrapper(42);
It does not prove anything of cause because it is undefined behavior (if it is UB).
Depending on what this function gets passed, it results in undefined behavior! More precisely, if you pass a non-lvalue, i.e. an rvalue, to this function, the value referenced by the returned reference will be stale.
Also
T&&
isn't a "universal reference" although the effect is somewhat like a universal reference in thatT
can be deduced asT&
orT const&
. The problematic case is when it gets deduced asT
: the arguments get passed in as temporary and die after the function returns but before anything can get hold of a reference to it.The use of
std::forward<T>(x)
is limited to, well, forwarding objects when calling another function: what came in as a temporary looks like an lvalue within the function. Usingstd::forward<T>(x)
letsx
look like a temporary if it came in as one - and, thus, allow moving fromx
when creating the argument of the called function.When you return an object from a function there are a few scenarios you might want to take care of but none of them involves
std::forward()
:const
or non-const
, you don't want to do anything with the object and just return the reference.return
statements use the same variable or all are using a temporary, copy/move elision can be used and will be used on decent compilers. Since the copy/move elision is an optimization, it doesn't necessarily happen, however.std::move()
to allow moving from the local object.In most of these cases the produced type is
T
and you should returnT
rather thanT&&
. IfT
is an lvalue type the result may not be an lvalue type, though, and it may be necessary to remove the reference qualification from the return type. In the scenario you specifically asked about the typeT
works.In the case that you do know that
t
will not be in a moved-from state after the call tof
, your two somewhat sensible options are:return
std::forward<T>(t)
with typeT&&
, which avoids any construction but allows for writing e.g.auto&& ref = wrapper(42);
, which leavesref
a dangling referencereturn
std::forward<T>(t)
with typeT
, which at worst requests a move construction when the parameter is an rvalue -- this avoids the above problem for prvalues but potentially steals from xvaluesIn all cases you need
std::forward
. Copy elision is not considered becauset
is always a reference.No you dont need to use
std::forward
better dont return r-value reference at all because it can prevent of NRVO optimization. You can read more about move semantics in this article: Article