I know the standard has an exception about extending the lifetime of temporaries that basically says binding a const reference in a constructor won't extend the lifetime, but does this also apply to literals? For example:
class C {
private:
const int& ref;
public:
C(const int& in)
: ref{in}
{ }
};
If I had a function returning an object of this type
C f() {
C c(2);
return c;
}
Would the value of c.ref
be undefined in the caller if I know it's bound to a literal?
No. You will not be able to use the reference after the constructor finishes execution.
When a prvalue of non-class type is bound to a const
-reference of that same type, a temporary is always introduced. Thus the constructor's parameter reference will refer to a temporary that is destroyed once the reference goes out of scope. After that happens, the member reference is dangling, and attempting to access the stored value behind that reference results in UB.
[dcl.init.ref]/5:
A reference to type “cv1
T1
” is initialized by an expression of type “cv2T2
” as follows:
- If the reference is an lvalue reference and the initializer expression
- is an lvalue (but is not a bit-field), and [..]
- has a class type (i.e.,
T2
is a class type) [..]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.
If the initializer expression
- is an xvalue (but not a bit-field), class prvalue, array prvalue or function lvalue and [..]
- has a class type [..]
Otherwise: (5.2.2.1)
- If
T1
is a class type [..]- If
T1
is a non-class type, a temporary of type “cv1T1
” is created and copy-initialized (8.5) from the initializer expression. The reference is then bound to the temporary.
And integer literals are, unsurprisingly, indeed prvalues. [expr.prim.general]/1:
A string literal is an lvalue; all other literals are prvalues.
Finally, in case this is unclear, [class.temporary]/5:
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 except:
- A temporary bound to a reference member in a constructor’s ctor-initializer (12.6.2) persists until the constructor exits.