A reference in C++ is an alias for another object. It can appear wherever the object it refers to can. The following program uses the reference iref as a substitute for i:
/* ref1.c: Illustrate references */
#include <stdio.h>
main()
{
int i = 10;
int &iref = i; // An alias for i
printf("%d\n",iref);
iref = 20;
printf("%d\n",i);
return 0;
}
/* Output:
10
20
*/
You can think of a reference as a "smart" pointer, since it refers to another object without requiring explicit addressing and dereferencing like pointers do:
/* ptr.c: Do the same thing with pointers */
#include <stdio.h>
main()
{
int i = 10;
int *iref = &i;
printf("%d\n" ,*iref);
*iref = 20;
printf("%d\n",i);
return 0;
}
The major differences between a pointer and a reference are:
- You must initialize a reference with the object it refers to. A declaration such as
int &iref;
is meaningless (except as a function parameter). Once initialized, you can't modify a reference to refer to a different object. Since a reference always refers to something, you don't need to check for NULL as you do with pointers.
References neither require nor allow the use of the & or * operators. All addressing and dereferencing are automatic. You can think of a reference as a const pointer that is derefenced each time it is used.
Like pointers, however, references can be function return values. Since a reference is by definition an lvalue, this allows the unusual practice of placing a function call on the left-hand side of an assignment:
/* ref2.cpp: Returning a reference */
#include <stdio.h>
int & current(); // Returns a reference
int a[4] = {0,1,2,3};
int index = 0;
main()
{
current() = 10;
index = 3;
current() = 20;
for (int i = 0; i < 4; ++i)
printf("%d ",a[i]);
putchar('\n');
return 0;
}
int & current()
{
return a[index];
}
/* Output:
10 1 2 20
*/
Another use for references is to implement pass-by-reference semantics, meaning that changes to function parameters persist in the calling procedure after the called function returns. You can do this with pointers, but references are cleaner:
/* ref3.cpp: Swap via references */
#include <stdio.h>
void swap(int &, int &);
main()
{
int i = 1, j = 2;
swap(i,j);
printf("i == %d, j == %d\n",i,j);
return 0;
}
void swap(int &x, int &y)
{
int temp = x;
x = y;
y = temp;
}
/* Output:
i==2, j == 1
*/
Even if you aren't going to modify a function parameter, it is a good idea to pass large objects by reference for efficiency. For example, if the data type X is large:
struct X
{
// lotsa stuff
};
then a function f that takes a parameter of type X, but doesn't modify it, should have a prototype similar to
void f(const X&);
For a more complete treatment of references, see Dan Saks' column in the September 1991 issue ("Reference Types", CUJ Vol. 9, No. 9).