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;          // valid

Note 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 extern specifier 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.
  • U is a class type.
  • T is not reference-related to U.
  • e can be converted to an lvalue of type S, and T is reference-compatible with S.

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; // ok
In 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.
IBM extension
If you specify the LANGLVL(COMPATRVALUEBINDING) option, the compiler can bind a non-const or volatile lvalue reference to an rvalue of a user-defined type where an initializer is not required. The default value of this option is LANGLVL(NOCOMPATRVALUEBINDING). This compiler behavior conflicts with the rvalue references feature, which does not allow a non-const or volatile lvalue reference to be bound to an rvalue. If both of the features are enabled, the compiler issues an error message.
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.
IBM extension
C++11
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
If an rvalue reference or a nonvolatile const lvalue reference 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.
  • U is a class type.
  • T is not reference-related to U.
  • e can be converted to an xvalue, class prvalue, or function lvalue type of S, and T is reference-compatible with S.

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.
C++11