Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Forwarding of return values. Is std::forward is needed?

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).

like image 539
Leonid Volnitsky Avatar asked Oct 18 '12 06:10

Leonid Volnitsky


People also ask

Why is STD forward needed?

std::forward The need for this function stems from the fact that all named values (such as function parameters) always evaluate as lvalues (even those declared as rvalue references), and this poses difficulties in preserving potential move semantics on template functions that forward arguments to other functions.

What is C++ perfect forwarding?

What is Perfect Forwarding. Perfect forwarding allows a template function that accepts a set of arguments to forward these arguments to another function whilst retaining the lvalue or rvalue nature of the original function arguments.

What is forwarding reference in C++?

When t is a forwarding reference (a function argument that is declared as an rvalue reference to a cv-unqualified function template parameter), this overload forwards the argument to another function with the value category it had when passed to the calling function.

What do std :: move and std :: forward do?

std::move takes an object and casts it as an rvalue reference, which indicates that resources can be "stolen" from this object. std::forward has a single use-case: to cast a templated function parameter of type forwarding reference ( T&& ) to the value category ( lvalue or rvalue ) the caller used to pass it.


1 Answers

In the case that you do know that t will not be in a moved-from state after the call to f, your two somewhat sensible options are:

  • return std::forward<T>(t) with type T&&, which avoids any construction but allows for writing e.g. auto&& ref = wrapper(42);, which leaves ref a dangling reference

  • return std::forward<T>(t) with type T, which at worst requests a move construction when the parameter is an rvalue -- this avoids the above problem for prvalues but potentially steals from xvalues

In all cases you need std::forward. Copy elision is not considered because t is always a reference.

like image 151
Luc Danton Avatar answered Sep 23 '22 03:09

Luc Danton