Reference initialization
Binds a reference to an object
Contents |
[edit] Syntax
T T T T |
(1) | ||||||||
T T T T |
(2) | (since C++11) | |||||||
given R fn ( T & arg ); or R fn ( T && arg );
fn fn |
(3) | ||||||||
inside T & fn () or T && fn ()
|
(4) | ||||||||
given T & ref ; or T && ref ; inside the definition of Class
Class |
(5) | ||||||||
[edit] Explanation
A reference to T
can be initialized with an object of type T
, a function of type T
, or an object implicitly convertible to T
. Once initialized, a reference cannot be changed to refer to another object.
References are initialized in the following situations:
The effects of reference initialization are:
- If the initializer is a braced-init-list
{
arg1, arg2, ...}
, rules of list initialization are followed.
- Otherwise, if the reference is an lvalue reference:
- If object is an lvalue expression, and its type is
T
or derived fromT
, and is equally or less cv-qualified, then the reference is bound to the object identified by the lvalue or to its base class subobject.
- If object is an lvalue expression, and its type is
double d = 2.0; double& rd = d; // rd refers to d const double& rcd = d; // rcd refers to d struct A {}; struct B : A {} b; A& ra = b; // ra refers to A subobject in b const A& rca = b; // rca refers to A subobject in b
- Otherwise, if the type of object is not same or derived from
T
, and object has conversion function to an lvalue whose type is eitherT
or derived fromT
, equally or less cv-qualified, then the reference is bound to the object identified by the lvalue returned by the conversion function (or to its base class subobject).
- Otherwise, if the type of object is not same or derived from
struct A {}; struct B : A { operator int&(); }; int& ir = B(); // ir refers to the result of B::operator int&
- Otherwise, if the reference is lvalue reference to const or rvalue reference (since C++11):
- If object is a non-bit-field rvalue or a function lvalue, and its type is either
T
or derived fromT
, equally or less cv-qualified, then the reference is bound to the value of the initializer expression or to its base subobject (after materializing a temporary if necessary) (since C++17).
- If object is a non-bit-field rvalue or a function lvalue, and its type is either
struct A {}; struct B : A {}; extern B f(); const A& rca2 = f(); // bound to the A subobject of the B rvalue. A&& rra = f(); // same as above int i2 = 42; int&& rri = static_cast<int&&>(i2); // bound directly to i2
- Otherwise, if the type of object is not same or derived from
T
, and object has conversion function to a rvalue or a function lvalue whose type is eitherT
or derived fromT
, equally or less cv-qualified, then the reference is bound to the result of the conversion function or to its base class subobject (after materializing a temporary if necessary) (since C++17).
- Otherwise, if the type of object is not same or derived from
struct A {}; struct B : A {}; struct X { operator B(); } x; const A& r = x; // bound to the A subobject of the result of the conversion B&& rrb = x; // bound directly to the result of the conversion
- Otherwise, object is implicitly converted to
T
. The reference is bound to the result of the conversion (after materializing a temporary) (since C++17). If the object (or, if the conversion is done by user-defined conversion, the result of the conversion function) is of typeT
or derived fromT
, it must be equally or less cv-qualified thanT
, and, if the reference is an rvalue reference, must not be an lvalue (since C++11).
- Otherwise, object is implicitly converted to
const std::string& rs = "abc"; // rs refers to temporary copy-initialized from char array const double& rcd2 = 2; // rcd2 refers to temporary with value 2.0 int i3 = 2; double&& rrd3 = i3; // rrd3 refers to temporary with value 2.0
[edit] Lifetime of a temporary
Whenever a reference is bound to a temporary or to a subobject thereof, the lifetime of the temporary is extended to match the lifetime of the reference, with the following exceptions:
- a temporary bound to a return value of a function in a return statement is not extended: it is destroyed immediately at the end of the return expression. Such function always returns a dangling reference.
|
(until C++14) |
- a temporary bound to a reference parameter in a function call exists until the end of the full expression containing that function call: if the function returns a reference, which outlives the full expression, it becomes a dangling reference.
- a temporary bound to a reference in the initializer used in a new-expression exists until the end of the full expression containing that new-expression, not as long as the initialized object. If the initialized object outlives the full expression, its reference member becomes a dangling reference.
struct A { int&& r; }; A a1{7}; // OK, lifetime is extended A a2(7); // well-formed, but dangling reference |
(since C++20) |
In general, the lifetime of a temporary cannot be further extended by "passing it on": a second reference, initialized from the reference to which the temporary was bound, does not affect its lifetime.
[edit] Notes
References appear without initializers only in function parameter declaration, in function return type declaration, in the declaration of a class member, and with the extern
specifier.
[edit] Example
#include <utility> #include <sstream> struct S { int mi; const std::pair<int, int>& mp; // reference member }; void foo(int) {} struct A {}; struct B : A { int n; operator int&() { return n; } }; B bar() { return B(); } //int& bad_r; // error: no initializer extern int& ext_r; // OK int main() { // Lvalues int n = 1; int& r1 = n; // lvalue reference to the object n const int& cr(n); // reference can be more cv-qualified volatile int& cv{n}; // any initializer syntax can be used int& r2 = r1; // another lvalue reference to the object n // int& bad = cr; // error: less cv-qualified int& r3 = const_cast<int&>(cr); // const_cast is needed void (&rf)(int) = foo; // lvalue reference to function int ar[3]; int (&ra)[3] = ar; // lvalue reference to array B b; A& base_ref = b; // reference to base subobject int& converted_ref = b; // reference to the result of a conversion // Rvalues // int& bad = 1; // error: cannot bind lvalue ref to rvalue const int& cref = 1; // bound to rvalue int&& rref = 1; // bound to rvalue const A& cref2 = bar(); // reference to A subobject of B temporary A&& rref2 = bar(); // same int&& xref = static_cast<int&&>(n); // bind directly to n // int&& copy_ref = n; // error: can't bind to an lvalue double&& copy_ref = n; // bind to an rvalue temporary with value 1.0 // Restrictions on temporary lifetimes std::ostream& buf_ref = std::ostringstream() << 'a'; // the ostringstream temporary // was bound to the left operand of operator<< // but its lifetime ended at the semicolon // so buf_ref is a dangling reference S a {1, {2, 3} }; // temporary pair {2, 3} bound to the reference member // a.mp and its lifetime is extended to match a S* p = new S{1, {2, 3} }; // temporary pair {2, 3} bound to the reference // member p->mp, but its lifetime ended at the semicolon // p->mp is a dangling reference delete p; }