Click here to Skip to main content
15,879,535 members
Articles / Programming Languages / C++

An Insight to References in C++

Rate me:
Please Sign up or sign in to vote.
3.52/5 (46 votes)
18 Apr 2006CPOL4 min read 163.7K   37   73
How C++ Compiler handles References

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: 

  1. Accessing/passing variable by value
  2. 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:

C++
#include <iostream.h>
int main()
{
    int i = 10;   // A simple integer variable
    int &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 reality
    return 0;
}

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)

C++
#include <iostream.h>
int main()
{
    int i = 10;   		// A simple integer variable
    int *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.
    return 0;
}

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:

C++
#include <iostream.h>
int main()
{
    int i = 10; // A Simple Integer variable
    int &j = i; // A Reference to the variable
    // Now we can also create a reference to reference variable. 
    int &k = j; // A reference to a reference variable
    // Similarly we can also create another reference to the reference variable k
    int &l = k; // A reference to a reference to a reference variable.

    // Now if we increment any one of them the effect will be visible on all the
    // variables.
    // First print original values
    // 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;
    return 0;
}

A sample C++ Code Using Reference Cascading (Compiler Generated Syntax)

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.

C++
#include <iostream.h>
int main()
{
    int i = 10;         // A Simple Integer variable
    int *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 k
    int *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;
    return 0;
}

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.

C++
#include <iostream.h>

class Test
{
    int &i;   // int *const i;
    int &j;   // int *const j;
    int &k;   // int *const k; 
};

int main()
{    
    // This will print 12 i.e. size of 3 pointers
    cout<<  "size of class Test = "  <<   sizeof(class Test)  <<endl;
    return 0;
}

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:

C++
#include <iostream.h>

class A
{
public:
	virtual void print() { cout<<"A.."<<endl; }
};

class B : public A
{
public:
	virtual void print() { cout<<"B.."<<endl; }
};

class C : public B
{
public:
	virtual void print() { cout<<"C.."<<endl; }
};

int main()
{
	C c1;
	A &a1 = c1;
	a1.print(); // prints C

 	A a2 = c1;
	a2.print(); // prints A
	return 0;
}

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.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Architect
India India
A programmer by heart since 1998. Written code in C++, Java, JavaScript, Python & Ruby, Worked on Stack Development to Web Development. Data Specialist with SQL and NoSQL DBs

Comments and Discussions

 
GeneralRe: Confusing article Pin
Ilya Lipovsky28-Apr-06 11:54
Ilya Lipovsky28-Apr-06 11:54 
GeneralRe: Confusing article Pin
jefito1-May-06 7:32
jefito1-May-06 7:32 
GeneralRe: Confusing article Pin
Ilya Lipovsky1-May-06 13:13
Ilya Lipovsky1-May-06 13:13 
GeneralRe: Confusing article Pin
jefito2-May-06 3:26
jefito2-May-06 3:26 
GeneralRe: Confusing article Pin
Ilya Lipovsky2-May-06 6:15
Ilya Lipovsky2-May-06 6:15 
GeneralRe: Confusing article Pin
jefito2-May-06 8:00
jefito2-May-06 8:00 
GeneralRe: Confusing article Pin
Ilya Lipovsky2-May-06 10:10
Ilya Lipovsky2-May-06 10:10 
GeneralRe: Confusing article Pin
jefito2-May-06 12:17
jefito2-May-06 12:17 
Before you complain any more about me not reading your posts (I have), perhaps you should go back and reaquaint yourself with my very first post on this topic, the first on in the thread, in which I discuss the possibility and even the reasonableness of implementing references with pointers, in some situations. I do not deny this, and never have -- I can't imagine why you would think from my postings that I could think this. Unless perhaps you never read what I wrote very carefully.

Because I have had this understanding all along, I have considered a lot of your and Gatik's examples irrelevant to the issues at hand (more left-handers, to continue my analogy of a couple of posts prior). You can stop repeating yourself -- whether a particular compiler actually implements references exactly the same as constant pointer doesn't matter in the least to me, and provides little, if any, help to the overall confusion of the article. It's why I can't be bothered to compile your code snippets with VC++ -- the result would really be irrelevant to my objects to the article.

Regarding context and the verb "obligate" -- I read what you wrote in the context you provided. How was I to know that when you wrote "obligated" you meant "permitted" or "might"?

Regarding gcc: it may or may not behave in the way that you describe. It doesn't matter a whit to me, so long as it meets the Standard with respect to references. I never claimed that it didn't, or made any claims about it's implementation. If you though that I did think any such thing, then please point out what I wrote that implied that.

Ultimately, my main point is, and has been, that the article's insistence that references are not aliases is incorrect, as is its implication that references must always take up memory space. The former is contradicted by the Standard and by reliable sources; the latter also by the Standard and by my own experiments. Will Gatik ever return to explain his use of the term 'alias', and his detestation of the very idea that a reference is an alias? Who knows?

But in the above light, I cannot help but wonder why it is that you so thoroughly agree with his conclusions. For example, you wrote:

I hope that Gatik will forgive me, if I interpret him that by saying that "many people think of a reference variable as an alias" he meant to say this:

Many people think that a declared&defined reference variable is interpreted by the compiler to be just another name for the original variable.

And that's as simple as that. Gatik then proceeded to say that the above notion is generally not true. What's your problem with that?

Gatik *does not say* that references are the same as const pointers. What he says is that they are the automatically dereferenced versions thereof. That's why in your code snippet:


My problem with that is that your restatement of Gatik's position (whether or not it accurately reflects his position), or at least what the statement's referenced "many people" think is actually always true at the level of C++, as supported by the Standard. How is a reference not an alias? At implementation level, a reference couldn't be an alias, because aliases don't exist in any machine code that I'm aware of. But that says nothing of interest, much the same as if he claimed that a reference is not a dog -- dog's don't exist in any machine code that I am aware of either. Quelle suprise.

Look, here's what he actually says in his introduction:

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


Is there anything there that paragraph that talks about anything at implementation level? No, it's all about the concept of references in C++.

Further, he says:
Gatik G wrote:
References are nothing but constant pointer in C++. A Statement int &i = j; will be converted by 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. Lets take the same example of references in C++ and this time we will use the syntax what compiler uses when it sees references.

...

The most important thing about the references is that its a type of pointer which gets automatically dereferenced (by compiler..).


So indeed he does actually say that references are nothing but const pointers (is an automatically dereferenced pointer somehow not a pointer? Are you confusing that with the result of a dereferenced pointer?). He makes assertions about the compiler that are unsupported (maybe we should change "will" to "might". Hmmm, sound familiar?) He makes claims about the syntax that the compiler uses when it sees references. Again, unsupported. More reading out of context? I don't think so. And he never, ever, allows for the possibility that a reference might not take up memory space.

I'm sorry, but his introduction is so riddled with confusion, that it's hardly useful to proceed with the remainder of his article. So why do you agree with him so happily?

And by the way, just what compilers are out of sync with the Standard with respect to references, and how do they differ? You said that they exist -- so what are they?

Jeff
GeneralRe: Confusing article Pin
Ilya Lipovsky2-May-06 13:09
Ilya Lipovsky2-May-06 13:09 
GeneralRe: Confusing article Pin
jefito3-May-06 11:21
jefito3-May-06 11:21 
GeneralRe: Confusing article Pin
Ilya Lipovsky2-May-06 10:39
Ilya Lipovsky2-May-06 10:39 
GeneralRe: Confusing article Pin
jefito19-Apr-06 9:22
jefito19-Apr-06 9:22 
GeneralRe: Confusing article Pin
itsdkg12-May-06 3:40
itsdkg12-May-06 3:40 
GeneralRe: Confusing article Pin
jefito13-May-06 17:18
jefito13-May-06 17:18 
GeneralRe: Confusing article Pin
Androne19-Apr-06 5:09
Androne19-Apr-06 5:09 
GeneralRe: Confusing article Pin
Kamal Barshevich8-Apr-21 8:16
Kamal Barshevich8-Apr-21 8:16 
GeneralCertain Inaccuracies Found Pin
Ilya Lipovsky14-Mar-06 8:46
Ilya Lipovsky14-Mar-06 8:46 
GeneralRe: Certain Inaccuracies Found Pin
Paulius Maruka14-Mar-06 12:41
Paulius Maruka14-Mar-06 12:41 
GeneralRe: Certain Inaccuracies Found Pin
Ilya Lipovsky14-Mar-06 15:15
Ilya Lipovsky14-Mar-06 15:15 
GeneralRe: Certain Inaccuracies Found Pin
Ilya Lipovsky14-Mar-06 15:28
Ilya Lipovsky14-Mar-06 15:28 
GeneralRe: Certain Inaccuracies Found Pin
itsdkg14-Mar-06 17:20
itsdkg14-Mar-06 17:20 
GeneralRe: Certain Inaccuracies Found Pin
Ilya Lipovsky14-Mar-06 18:58
Ilya Lipovsky14-Mar-06 18:58 
GeneralRe: Certain Inaccuracies Found Pin
Ilya Lipovsky14-Mar-06 19:00
Ilya Lipovsky14-Mar-06 19:00 
GeneralThe purpose of references Pin
podfish14-Mar-06 8:19
podfish14-Mar-06 8:19 
GeneralAnother important thing about reference Pin
Linlin Yan10-Mar-06 3:39
Linlin Yan10-Mar-06 3:39 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.