mirror of
https://github.com/isocpp/CppCoreGuidelines.git
synced 2025-12-17 12:44:42 +03:00
Resolve #1241 about returning T&&
This commit is contained in:
@@ -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 `&&`.
|
||||
|
||||
Reference in New Issue
Block a user