Resolve #1241 about returning T&&

This commit is contained in:
Bjarne Stroustrup
2018-09-03 10:04:48 -04:00
parent e31a85dc2d
commit dd4cae0260
3 changed files with 717 additions and 8 deletions

View File

@@ -3600,32 +3600,48 @@ Flag functions where no `return` expression could yield `nullptr`
##### Reason
It's asking to return a reference to a destroyed temporary object. A `&&` is a magnet for temporary objects. This is fine when the reference to the temporary is being passed "downward" to a callee, because the temporary is guaranteed to outlive the function call (see [F.18](#Rf-consume) and [F.19](#Rf-forward)). However, it's not fine when passing such a reference "upward" to a larger caller scope. See also ???.
It's asking to return a reference to a destroyed temporary object.
A `&&` is a magnet for temporary objects.
##### Example
A returned rvalue reference goes out of scope at the end of the full expression to which it is returned:
auto&& x = max(0,1); // OK, so far
foo(x); // Unfefined behavior
This kind of use is a frequent source of bugs, often incorrectly reported as a compiler bug.
An implementer of a function should avoid setting such traps for users.
The [lifetipe safety profile](#SS-lifetime) will (when completely implemented) catch such problems
##### Example
Returning an rvalue reference is fine when the reference to the temporary is being passed "downward" to a callee;
then, the temporary is guaranteed to outlive the function call (see [F.18](#Rf-consume) and [F.19](#Rf-forward)).
However, it's not fine when passing such a reference "upward" to a larger caller scope.
For passthrough functions that pass in parameters (by ordinary reference or by perfect forwarding) and want to return values, use simple `auto` return type deduction (not `auto&&`).
##### Example, bad
If `F` returns by value, this function returns a reference to a temporary.
Assume that `F` returns by value:
template<class F>
auto&& wrapper(F f)
{
log_call(typeid(f)); // or whatever instrumentation
return f();
return f(); // BAD: eturns a reference to a temporary
}
##### Example, good
Better:
template<class F>
auto wrapper(F f)
{
log_call(typeid(f)); // or whatever instrumentation
return f();
return f(); // OK
}
##### Exception
`std::move` and `std::forward` do return `&&`, but they are just casts -- used by convention only in expression contexts where a reference to a temporary object is passed along within the same expression before the temporary is destroyed. We don't know of any other good examples of returning `&&`.