return const reference vs temporary object
Even if you assign it to a const reference, the return value is declared as passed by value, that means it'll be copied[1] to outside as a temporary object, and then binded to the const reference. Binding temporary object to a const reference is fine, the object won't be destroyed until getting out of the lifetime of the const reference.
On the other hand, returning reference of a local variable is illegel. The local variable'll be destroyed when the function returned, that means the outside reference will be dangled.
EDIT
My point is that if assigning a const ref to a returned local variable is legal, then shouldn't assigning a const ref to a returned const ref of a local variable be legal as well?
The point is the 1st case is not assigning a const ref to a returned local variable, it's assigning a const ref to a returned temporary variable. (Which might copied from the local variable.)
[1] The copy might be omitted according to RVO technically.
Returning temporary object and binding to const reference
This is a C++ feature. The code is valid and does exactly what it appears to do.
Normally, a temporary object lasts only until the end of the full expression in which it appears. However, C++ deliberately specifies that binding a temporary object to a reference to const on the stack lengthens the lifetime of the temporary to the lifetime of the reference itself, and thus avoids what would otherwise be a common dangling-reference error. In the example above, the temporary returned by foo()
lives until the closing curly brace.
P.S: This only applies to stack-based references. It doesn’t work for references that are members of objects.
Full text: GotW #88: A Candidate For the “Most Important const” by Herb Sutter.
Does const reference prolong the life of a temporary object returned by a temporary object?
The lifetime extension only applies when a reference is directly bound to that temporary.
For example, initializing another reference from that reference does not do another extension.
However, in your code:
std::string const& foo = aBar.getTemporaryObject1().getTemporaryObject2();
You are directly binding foo
to the return value of getTemporaryObject2()
, assuming that is a function that returns by value. It doesn't make a difference whether this was a member function of another temporary object or whatever. So this code is OK.
The lifetime of the object returned by getTemporaryObject1()
is not extended but that doesn't matter (unless getTemporaryObject2
's return value contains references or pointers to that object, or something, but since it is apparently a std::string
, it couldn't).
const reference to member of temporary object
Yes, this code is perfectly acceptable. The rules, according to the standard are ([class.temporary]):
There are two contexts in which temporaries are destroyed at a
different point than the end of the fullexpression. The first context
is when a default constructor is called to initialize an element of an
array. If the constructor has one or more default arguments, the
destruction of every temporary created in a default argument is
sequenced before the construction of the next array element, if any.The second context is when a reference is bound to a temporary. The
temporary to which the reference is bound or the temporary that is the
complete object of a subobject to which the reference is bound
persists for the lifetime of the reference...
As you can see the highlighted line makes it clear that binding reference to sub-objects is acceptable, as the complete object has to have its lifetime extended as well.
Note that first
does qualify as a subobject [intro.object]:
- Objects can contain other objects, called subobjects. A subobject can
be a member subobject (9.2), a base class subobject (Clause 10), or an
array element. An object that is not a subobject of any other object
is called a complete object.
about returning a const reference to a temporary argument
The behaviour is undefined.
Binding a const
reference to an anonymous temporary extends the lifetime of that anonymous temporary to the lifetime of that const
reference.
But the attempted re-binding of the returned reference to a
in foo
will not extend the lifetime: lifetime extension is not transitive. So a
is a dangling reference in main()
.
why can temporary objects be bound to const reference?
If the object is temporary, why would making the reference
const
have any effect on the lifetime of the temporary object?
In the present context, the issue is not the lifetime of the object but whether you can modify it.
Say you make a call.
foo(10);
The object that holds the value 10
in the call should not be modified by the function. If the interface of foo
is:
void foo(int& ref);
it's fair to implement foo
as:
void foo(int& ref)
{
ref = 20;
}
That would be a problem given the call foo(10)
. It won't be a problem if foo
uses a const&
.
void foo(int const& ref)
{
ref = 20; // Not allowed.
}
From C++11 Standard, Temporary Objects/1
Temporaries of class type are created in various contexts: binding a reference to a prvalue ([dcl.init.ref]), returning a prvalue ([stmt.return]), a conversion that creates a prvalue, ...
and from C++11 Standard, References/5.2:
-- Otherwise, the reference shall be an lvalue reference to a non-volatile const type (i.e., cv1 shall be const), or the reference shall be an rvalue reference.
A temporary can only bind to a reference to a prvalue. The type of such a reference must be a const
qualified lvalue reference or a rvalue references.
MS Visual Studio compilers have allowed binding of non-const
references to temporary objects but it is not sanctioned by the standard.
About binding a const reference to a sub-object of a temporary
This is covered by CWG 1651:
The resolution of issues 616 and 1213, making the result of a member
access or subscript expression applied to a prvalue an xvalue, means
that binding a reference to such a subobject of a temporary does not
extend the temporary's lifetime. 12.2 [class.temporary] should be
revised to ensure that it does.
The status quo is that only prvalues are treated as referring to temporaries - thus [class.temporary]/5 ("The second context is when a reference is bound to a temporary.") is not considered applicable. Clang and GCC have not actually implemented issue 616's resolution, though. center().x
is treated as a prvalue by both. My best guess:
GCC simply didn't react to any DRs yet, at all. It doesn't extend lifetime when using scalar subobjects, because those are not covered by [dcl.init.ref]/(5.2.1.1)†. So the complete temporary object doesn't need to live on (see aschelper's answer), and it doesn't, because the reference doesn't bind directly. If the subobject is of class or array type, the reference binds directly, and GCC extends the temporary's lifetime. This has been noted in DR 60297.
Clang recognizes member access and implemented the "new" lifetime extension rules already - it even handles casts. Technically speaking, this is not consistent with the way it handles value categories. However, it is more sensible and will be the correct behavior once the aforementioned DR is resolved.
I'd therefore say that GCC is correct by current wording, but current wording is defective and vague, and Clang already implemented the pending resolution to DR 1651, which is N3918. This paper covers the example very clearly:
If
E1
is a temporary expression andE2
does not designate a
bit-field, thenE1.E2
is a temporary expression.
center()
is a temporary expression as per the paper's wording for [expr.call]/11. Thus its modified wording in the aforementioned [class.temporary] /5 applies:
The second context is when a reference does not bind directly (8.5.3
dcl.init.ref) or is initialized with a temporary expression (clause 5). The corresponding temporary
object (if any) persists for the lifetime of the reference except: [...inapplicable exceptions...]
Voilà, we have lifetime extension. Note that "the corresponding temporary object" is not clear enough, one of the reasons for the proposal's deferment; it will assuredly be adopted once it gets revised.
†
is an xvalue (but not a bit-field), class prvalue, array prvalue or function lvalue and “
cv1 T1
” is reference-compatible with “cv2 T2
”, or […]
Indeed, GCC respects this fully and will extend lifetime if the subobject has array type.
Related Topics
How to Measure CPU Time of a Specific Set of Threads
How to Detect the Number of Physical Processors/Cores on Windows, MAC and Linux
How to Make Std::Vector's Operator[] Compile Doing Bounds Checking in Debug But Not in Release
When to Use the Brace-Enclosed Initializer
How to Simulate "Press Any Key to Continue"
Efficient 128-Bit Addition Using Carry Flag
Why Are Rvalues References Variables Not Rvalue
How to Avoid Multiple Definition Linking Error
While (1) VS. for (;;) Is There a Speed Difference
How to Initialize Std::Array<T, N> Elegantly If T Is Not Default Constructible
When to Use Std::Forward to Forward Arguments
Is There Any "Standard" Htonl-Like Function for 64 Bits Integers in C++
Why Is Including "Using Namespace" into a Header File a Bad Idea in C++
May I Take the Address of the One-Past-The-End Element of an Array