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 non-volatile const lvalue reference, which can be initialized with the temporary initialized with the rvalue expression 1.
IBM extension
If you specify the -qlanglvl=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 -qlanglvl=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. For details of the rvalue references feature, see Using rvalue references (C++11).
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 non-volatile 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 non-volatile 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