Initialization of references (C++ only)
When you initialize a reference, you bind that reference to an object, which is not necessarily the object denoted by the initializer expression.
Once a reference has been initialized, it cannot be modified
to refer to another object. For example:
int num1 = 10;
int num2 = 20;
int &RefOne = num1; // valid
int &RefOne = num2; // error, two definitions of RefOne
RefOne = num2; // assign num2 to num1
int &RefTwo; // error, uninitialized reference
int &RefTwo = num2; // validNote that the initialization of a reference is not the same as an assignment to a reference. Initialization operates on the actual reference by binding the reference to the object it is an alias for. Assignment operates through the reference on the object referred to.
A reference can be declared without an initializer:
- When it is used in a parameter declaration
- In the declaration of a return type for a function call
- In the declaration of class member within its class declaration
- When the
externspecifier is explicitly used
Reference binding
Suppose
T and U are
two types. If ignoring top-level cv-qualifiers, T is
of the same type as U or is a base class of U, T and U are reference-related.Example 1
typedef int t1;
typedef const int t2;In this example, t1 and t2 are
reference-related.If T and U are
reference-related, and T is at least as cv-qualified
as U, T is reference-compatible with U.
In Example 1, t1 is not reference-compatible with t2,
but t2 is reference-compatible with t1.
If
an lvalue reference
r to type T is
to be initialized by an expression e of type U,
and T is reference-compatible with U,
the reference r can be bound directly to e or
a base class subobject of e unless T is
an inaccessible or ambiguous base class of U. Example 2
int a = 1;
const int& ra = a;
struct A {};
struct B: A {} b;
A& rb = b;In this example, the const int type
is reference-compatible with the int type, so ra can
be bound directly to a. Structure A is
reference-related to structure B, so rb can
be bound directly to b.If an lvalue reference
r to
type T is to be initialized by an expression e of
type U, r can be bound to the lvalue
result of the conversion of e or a base class of e if
the following conditions are satisfied. In this case, the conversion
function is chosen by overload resolution.Uis a class type.Tis not reference-related toU.ecan be converted to an lvalue of typeS, andTis reference-compatible withS.
Example 3
struct A {
operator int&();
};
const int& x= A(); In this example, structure A is
a class type, and the const int type is not reference-related
to structure A. However, A can be
converted to an lvalue of type int, and const
int is reference-compatible with int, so
reference x of type const int can
be bound to the conversion result of A().By
default, the compiler cannot bind a non-const or volatile lvalue reference
to an rvalue.
Example 4
int& a = 2; // error
const int& b = 1; // okIn this example, the variable a is
a non-const lvalue reference. The compiler cannot bind a to
the temporary initialized with the rvalue expression 2,
and issues an error message. The variable b is a
nonvolatile const lvalue reference, which can be initialized with
the temporary initialized with the rvalue expression 1.
Notes:
- A non-const or volatile lvalue reference cannot be bound to an rvalue of a built-in type.
- A non-const or volatile lvalue reference that is a class member cannot be bound to an rvalue.


Suppose an expression
e of
type U belongs to one of the following value categories:- An xvalue
- A class prvalue
- An array prvalue
- A function lvalue
r to
type T is to be initialized by the expression e,
and T is reference-compatible with U,
reference r can be initialized by expression e and
bound directly to e or a base class subobject of e unless T is
an inaccessible or ambiguous base class of U. Example 5
int& func1();
int& (&&rf1)()=func1;
int&& func2();
int&& rf2 = func2();
struct A{
int arr[5];
};
int(&&ar_ref)[5] = A().arr;
A&& a_ref = A();
In this example, rf1, rf2, ar_ref,
and a_ref are all rvalue references. rf1 is
bound to the function lvalue func1, rf2 is
bound to the xvalue result of the call func2(), ar_ref is
bound to the array prvalue A().arr, and a_ref is
bound to the class prvalue A().Suppose
r is
an rvalue reference or nonvolatile const lvalue reference to type
T, and r is to be initialized by an expression e of
type U. r can be bound to the conversion
result of e or a base class of e if
the following conditions are satisfied. In this case, the conversion
function is chosen by overload resolution.Uis a class type.Tis not reference-related toU.ecan be converted to an xvalue, class prvalue, or function lvalue type ofS, andTis reference-compatible withS.
Example 6
int i;
struct A {
operator int&&() {
return static_cast<int&&>(i);
}
};
const int& x = A();
int main() {
assert(&x == &i);
} In this example, structure A is a
class type, and the const int type is not reference-related
to structure A. However, A can be
converted to an xvalue of type int, and const
int is reference-compatible with int, so
reference x of const int can be
initialized with A() and bound to variable i. An
rvalue reference can be initialized with an lvalue in the following
contexts:
- A function lvalue
- A temporary converted from an lvalue
- An rvalue result of a conversion function for an lvalue object that is of a class type
Example 7
int i = 1;
int&& a = 2; // ok
int&& b = i; // error
double&& c = i; // ok
In this example, the rvalue reference a can
be bound to the temporary initialized with the rvalue expression 2,
but the rvalue reference b cannot be bound to the
lvalue expression i. You can bind the rvalue reference c to
the temporary value 1.0 that is converted from the
variable i.