Reference (C++)


In the C++ programming language, a reference is a simple reference datatype that is less powerful but safer than the pointer type inherited from C. The name C++ reference may cause confusion, as in computer science a reference is a general concept datatype, with pointers and C++ references being specific reference datatype implementations. The definition of a reference in C++ is such that it does not need to exist. It can be implemented as a new name for an existing object.

Syntax and terminology

The declaration of the form:
&
where is a type and is an identifier whose type is reference to .
Examples:

int a = 5;
int& r_a = a;
extern int& r_b;

Here, r_a and r_b are of type "reference to int"
int& Foo;
Foo is a function that returns a "reference to int"
void Bar;
Bar is a function with a reference parameter, which is a "reference to int"
class MyClass ;
MyClass is a class with a member which is reference to int

int FuncX ;
int = FuncX;

FuncX is a function that returns a int and f_func is an alias for FuncX
const int& ref = 65;
const int& ref is a constant reference pointing to a piece of storage having value 65.
Types which are of kind "reference to " are sometimes called reference types. Identifiers which are of reference type are called reference variables. To call them variable, however, is in fact a misnomer, as we will see.

Relationship to pointers

C++ references differ from pointers in several essential ways:
  • It is not possible to refer directly to a reference object after it is defined; any occurrence of its name refers directly to the object it references.
  • Once a reference is created, it cannot be later made to reference another object; it cannot be reseated. This is often done with pointers.
  • References cannot be null, whereas pointers can; every reference refers to some object, although it may or may not be valid. Note that for this reason, containers of references are not allowed.
  • References cannot be uninitialized. Because it is impossible to reinitialize a reference, they must be initialized as soon as they are created. In particular, local and global variables must be initialized where they are defined, and references which are data members of class instances must be initialized in the initializer list of the class's constructor. For example:
  • :
int& k; // compiler will complain: error: `k' declared as reference but not initialized

There is a simple conversion between pointers and references: the address-of operator will yield a pointer referring to the same object when applied to a reference, and a reference which is initialized from the dereference of a pointer value will refer to the same object as that pointer, where this is possible without invoking undefined behavior. This equivalence is a reflection of the typical implementation, which effectively compiles references into pointers which are implicitly dereferenced at each use. Though that is usually the case, the C++ Standard does not force compilers to implement references using pointers.
A consequence of this is that in many implementations, operating on a variable with automatic or static lifetime through a reference, although syntactically similar to accessing it directly, can involve hidden dereference operations that are costly.
Also, because the operations on references are so limited, they are much easier to understand than pointers and are more resistant to errors. While pointers can be made invalid through a variety of mechanisms, ranging from carrying a null value to out-of-bounds arithmetic to illegal casts to producing them from arbitrary integers, a previously-valid reference only becomes invalid in two cases:
  • If it refers to an object with automatic allocation which goes out of scope,
  • If it refers to an object inside a block of dynamic memory which has been freed.
The first is easy to detect automatically if the reference has static scoping, but is still a problem if the reference is a member of a dynamically allocated object; the second is more difficult to detect. These are the only concerns with references, and are suitably addressed by a reasonable allocation policy.

Uses of references

  • Other than just a helpful replacement for pointers, one convenient application of references is in function parameter lists, where they allow passing of parameters used for output with no explicit address-taking by the caller. For example:

void Square

Then, the following call would place 9 in y:

int y;
Square;

However, the following call would give a compiler error, since reference parameters not qualified with const can only be bound to addressable values:
Square;
  • Returning a reference allows function calls to be assigned to:
int& Preinc
Preinc = 5; // same as ++y, y = 5
  • In many implementations, normal parameter-passing mechanisms often imply an expensive copy operation for large parameters. References qualified with const are a useful way of passing large objects between functions that avoids this overhead:
void FSlow
void FFast
BigObject y;
FSlow; // Slow, copies y to parameter x.
FFast; // Fast, gives direct read-only access to y.

If FFast actually requires its own copy of x that it can modify, it must create a copy explicitly. While the same technique could be applied using pointers, this would involve modifying every call site of the function to add cumbersome address-of operators to the argument, and would be equally difficult to undo, if the object became smaller later on.

Polymorphic behavior

Continuing the relationship between references and pointers, the former exhibit polymorphic capabilities, as one might expect:

  1. include
class A ;
class B : public A ;
int main

The source above is valid C++ and generates the following output:


This is class A
This is class B

ISO definition

References are defined by the ISO C++ standard as follows :