An Insight to References in C++

Introduction

I choose to write about references in C++ because I feel most of the people have misconceptions about references. I got this feeling because I took many C++ interviews and I seldom get correct answers about references in C++.

What is meant by references in C++? A reference is generally thought of as an aliasing of the variable it refers to. I hate the definition of references being an alias of a variable in C++. In this article, I will try to explain that there is nothing known as aliasing in C++.

Background

Both in C and in C++, there are only two ways by which a variable can be accessed, passed, or retrieved. The two ways are:

Accessing/passing variable by value

Accessing/Passing variable by address - In this case pointers will come into the picture

There is no 3rd way of accessing/passing variables. A reference variable is just another pointer variable which will take its own space in memory. The most important thing about the references is that it's a type of pointer which gets automatically dereferenced (by compiler). Hard to believe? Let's see....

A Sample C++ Code using References

Lets write a simple C++ code which will use references:

#include<iostream.h>int main()
{
int i = 10; // A simple integer variableint &j = i; // A Reference to the variable i
j++; // Incrementing j will increment both i and j.// check by printing values of i and j
cout<< i << j <<endl; // should print 11 11// Now try to print the address of both variables i and j
cout<< &i << &j <<endl;
// surprisingly both print the same address and make us feel that they are// alias to the same memory location. // In example below we will see what is the realityreturn0;
}

References are nothing but constant pointers in C++. A statement int &i = j; will be converted by the compiler to int *const i = &j; i.e. References are nothing but constant pointers. They need initialization because constants must be initialized and since the pointer is constant, they can't point to anything else. Let's take the same example of references in C++ and this time we will use the syntax that the compiler uses when it sees references.

A Sample C++ Code using References (Compiler Generated Syntax)

#include<iostream.h>int main()
{
int i = 10; // A simple integer variableint *const j = &i; // A Reference to the variable i
(*j)++; // Incrementing j. Since reference variables are // automatically dereferenced by compiler// check by printing values of i and j
cout<< i << *j <<endl; // should print 11 11// A * is appended before j because it used to be reference variable// and it should get automatically dereferenced.return0;
}

You must be wondering why I skipped the printing of address from the above example. This needs some explanation. Since reference variables are automatically dereferenced, what will happen to a statement like cout << &j << endl;. The compiler will convert the statement into cout << &*j << endl; because the variable gets automatically dereferenced. Now &* cancels each other. They become meaningless and cout prints the value at j which is nothing but the address of i because of the statement int *const j = &i;.

So the statement cout << &i << &j << endl; becomes cout << &i << &*j << endl; which is similar to printing the address of i in both the cases. This is the reason behind the same address being displayed while we try to print normal variables as well as reference variables.

A Sample C++ Code using Reference Cascading

Here we will try to look at a complex scenario and see how references will work in cascading. Let's follow the code below:

Here we will see if we won't depend upon the compiler to generate constant pointers in place of reference and auto dereferencing the constant pointer, we can achieve the same results.

#include<iostream.h>int main()
{
int i = 10; // A Simple Integer variableint *const j = &i; // A Reference to the variable// The variable j will hold the address of i// Now we can also create a reference to reference variable. int *const k = &*j; // A reference to a reference variable// The variable k will also hold the address of i because j // is a reference variable and // it gets auto dereferenced. After & and * cancels each other // k will hold the value of// j which it nothing but address of i// Similarly we can also create another reference to the reference variable kint *const l = &*k; // A reference to a reference to a reference variable.// The variable l will also hold address of i because k holds address of i after// & and * cancels each other.// so we have seen that all the reference variable will actually holds the same// variable address.// Now if we increment any one of them the effect will be visible on all the// variables.// First print original values. The reference variables will have * prefixed because // these variables gets automatically dereferenced.// The print should be 10,10,10,10
cout<< i << "," << *j << "," << *k << "," << *l <<endl;
// increment variable j
(*j)++;
// The print should be 11,11,11,11
cout<< i << "," << *j << "," << *k << "," << *l <<endl;
// increment variable k
(*k)++;
// The print should be 12,12,12,12
cout<< i << "," << *j << "," << *k << "," << *l <<endl;
// increment variable l
(*l)++;
// The print should be 13,13,13,13
cout << i << "," << *j << "," << *k << "," << *l <<endl;
return0;
}

A Reference Takes its Own Space in Memory

We can see this by checking the size of the class which has only reference variables. The example below proofs that a C++ reference is not an alias and takes its own space into the memory.

Conclusion

I hope that this article explains everything about C++ references. However I'd like to mention that C++ standard doesn't explain how reference behaviour should be implemented by the compiler. It's up to the compiler to decide, and most of the time it is implemented as a constant pointer.

Additional Notes to Support this Article

In the discussion forums for this article, people were having concerns that References are not constant pointers but aliases. I am writing one more example to support this fact. Look carefully at the example below:

The example using references supports the virtual mechanism, i.e. looking into the virtual pointer to get the handle to correct function pointer. The interesting thing here is how the virtual mechanism is supported by the static type which is simply an alias. Virtual mechanism is supported by dynamic information which will come into the picture only when a pointer is involved. I hope this will clarify most of the doubts.

The article's fine as far as it goes, but it doesn't go nearly far enough. Sure, references are typically implemented as constant pointers, and usually do take space in memory - though there's no requirement that either of those points is true.
The purpose of language constructs is to let you get away from such implementation details - they are there to help think about the problem you're solving. It may help understanding to look at implementation, or it may distract you from the real point. Here I think it's distracted you.
There are two key differences between references and pointers that you must consider when deciding which to use: pointers can be NULL and they can point to different target objects over their lifetime.
So the earlier comment about their suitability for parameter passing is spot on. A good use for a reference is in the case where you're passing a big object "by reference" (thus the name!) and you guarantee that it's always going to be a valid object.
Another good place to use references is in a class, where you're going to want a permanent connection to another object, and again can guarantee that the lifetime of the target object is at least as great as your container.

Regarding the code snippet in last section "A Reference takes its own space in memory", it does not prove that reference takes its own space in memory as integer is usually the same size as pointer on a 32 bit system.

The C++ standard only describes the behaviour of references; it does not say how they are implemented. Commonly they are in fact implemented as const pointers behind the scenes and it may be helpful to point that out. However, that is an implementation detail, not part of the definition of a reference.

John Carson

"To argue with a man who has renounced the use and authority of reason is like administering medicine to the dead."
Thomas Paine

The only point the article makes is that references in C++ are nothing but constant pointers. The section A Reference takes its own space in memory is rather redundant and perhaps somewhat misleading to beginners. It goes without saying that a pointer takes memory space if you want to save it in a structure or a class as in the example.

However, I still vote a score of 4 for the article, holding 1 point off for wrong difficulty labeling and redundant sections.

I didn't know this implementation detail before reading this article and I haven't been a beginner for a rather long time. I am sure I am not alone in not knowing this detail in spite of being experienced.

Because I use the abstraction, I haven't needed to know the details, either. My life is generally easier and my code simpler and easier to maintain because of the use of abstractions, and that is really the whole point behind using an object-oriented language.

Knowing such details can be interesting and can sometimes be helpful: as a foundation of knowledge, if something isn't working as expected (in this case rather unlikely), or if one is interested in writing compilers, but seldom is it anything a beginner needs to know. This article is really rather esoteric - interesting, but esoteric.