All about References in C++:

Mridula's Avatar author of All about References in C++:
This is an article on All about References in C++: in C++.

Introduction



This article talks about References in C++ with some examples.

Background



Reference:

A Reference is nothing but an Alias to an existing variable.

Characteristics:
  1. It is always declared along with an Assignment/Initilization to an existing varible, called as Referent.
  2. Declaring a Reference establishes a new name as an alias to an existing variable.
  3. As it is just an Alias to an existing variable, it can never be initialised or set to NULL value.
  4. Once it is Declared and Aliased to a variable, it is not possible to re-set to refer another variable.

Reference and Referent
  • Address of a Reference and it's Referent are always same.

Example 1:



Code: Cpp
#include<iostream.h>

int main()
{
  int a;
  int &b=a;

  cout<<"Address of a: "<<&a<<endl;
  cout<<"Address of b: "<<&b<<endl;

  return(0);
}

output
-------

Address of a: 0xffbee81c
Address of b: 0xffbee81c

  • Assigning a value to a Reference would change the value of it's Referent too.

Example 2:



Code: Cpp
#include<iostream.h>

int main()
{
    int data1;
    data1 = 10;

    int &ref = data1;

    cout<<"Value of a Reference ref is :"<<ref<<endl;
    cout<<"Value of a Referent data1 is :"<<data1<<endl;

    //Assigning a different value to ref
    ref++;
   
    cout<<"Value of a Reference ref is :"<<ref<<endl;
    cout<<"Value of a Referent data1 is :"<<data1<<endl;

    return(0);
}

output
--------
Value of a Reference ref is :10
Value of a Referent data1 is :10
Value of a Reference ref is :20
Value of a Referent data1 is :20

  • Once a Reference is Declared and Initialized to refer to one variable then it can never be Re-refered to another variable. Otherway, it is always Initialized to it's Referent as soon as it is Declared, so we can never separate the Reference from it's Referent. Means, we cannot Re-Declare and Re-Initialize a Reference. Below example ensures this point.

Example 3:



Code: Cpp
#include<iostream.h>

int main()
{
    int &ref;

    return(0);
}

Compiler error!!
ref6.cc:5: error: `ref' declared as reference but not initialized

Reference as Parameter/Argument

References are mostly used for pass-by-reference method for function's arguments.
  • This enforces contracts at compile-time rather than at run-time wherever possible.
  • Passing all but small objects by Reference would improve performance as it is faster than passing them by value (because it does not need to make a copy of the object).
  • When a Reference is passed as an argument, a copy of the objects address is passed. This makes sure of, one fewer level of indirection to refer the original object than when a pointer to the original object, is passed as an argument.
  • Also, we can avoid un-intentional changes to the original object by making the passed Reference object as const.

Example of Reference as a Parameter.

Example 4:



Code: Cpp
#include<iostream.h>

void increFunc(int &i)
{
    ++i;
}

int main()
{
   int data;
   data = 10;
   cout<<"Value of data: "<<data<<endl;
   
   increFunc(data);
   cout<<"Value of data: "<<data<<endl;
     
   return(0);
}

Output:
---------
Value of data: 10
Value of data: 11

When to use Reference as an Argument to a function
  • When there is a requirement that we have to Refer to/work on an original object and when we also have to make sure of not refering to anything else i.e. other than that original object, then use a Reference else use a Pointer.
  • If it is not acceptable for the caller of the function to pass nothing/NULL, then do pass a Reference because it cannot be initialized with a null value.
  • For large structures or objects passed to a function or method, a Reference is sometimes used to avoid the expense of a copy operation (when we pass them by pass-by-value way), even though the structure or object passed is not going to be modifed.

Return by Reference

By returning a Reference, a function call can be made as lvalue.

Example 5:



Code: Cpp
#include<iostream.h>

int & func(int &k)
{
    ++k;
    return(k);
}

int main()
{
    int data;
    data = 0;
   
    cout<<"Value of data: "<<data<<endl;

    func(data) += 10;
   
    cout<<"Value of data: "<<data<<endl;

    return(0);
}

Output
------
Value of data: 0
Value of data: 11

We must be careful while returning a Reference. As we should not be returning a Reference to a local variable or variable that is declared in stack. To avoid the risk of mis-using of this concept, it is recommended that never return a Reference from a function.

Implementation of a Reference

A Reference is nothing but an object and it takes it's own space in memory.

If we think of it's implementation, it is typically initialized with the Referent's address. And compiler is designed such a way that any modification to the Reference will modifiy even the Referent (object) as well as shown above in Example 2.

References compared to Pointers
  • Reference variables MUST be initialized, where as Pointers need not be.
  • We cannot change/modify a Reference variable to refer to some other variable/Referent, whereas we can change a pointer to point to some other variable.
  • Pointer arithmetic can be done with Pointers, we cannot do it with References.
  • We have to derefence (* or ->) the pointers to fetch the data, whereas we can directly get data by accessing a Reference.
  • Pointers may be null, whereas Reference cannot be NULL.
  • References are usually preferred over pointers, whenever we don't need to reset them.
  • References can be called as constant pointers.

Did you know?
  • We can have a Reference to a Reference !!

Example 6:



Code: Cpp
#include<iostream.h>

int main()
{
  int data = 10;
  int &ref = data;
  cout<<"\nReference ref value: "<<ref<<endl;
 
  int &ref2Ref =ref;
  cout<<"Reference ref2Ref value: "<<ref2Ref<<endl;

  return(0)
}

output
-------
Reference ref value: 10
Reference ref2Ref value: 10

  • The size of a object of a Class, that has a Reference variable, includes the size of that Reference as well !!

Example 7:


This example ensures that Reference takes it's own space in memory.

Code: Cpp
#include<iostream.h>

class A{
  int &a;
  int b;
    public: A():a(b), b(0){};
            ~A(){};
};

int main()
{
  A a;
  cout<<"Size of object :a: is := "<<sizeof(a)<<endl;
  return(0);
}

output:
--------

Size of object :a: is := 8

  • We must always initialize the Reference member variable of a Class in it's Initialization List of it's constructor as shown above. Else there will be a compilation error!!

Example 8:



Code: Cpp
#include<iostream.h>

class A{
  int &a;
  int b;
 
  public: A(){};
          ~A(){};
};

int main()
{
  A a;
  return(0);
}

Compiler Error
-----------------
ref5.cc:7: error: uninitialized reference member `A::a'

Disadvantage(s)

It is more difficult to ensure, a Reference becoming invalid, if it refers to an object inside a block of dynamic memory which has been freed.

Example 9:


Here in this example, though the memory allocated to ptr variable is freed, but still Reference variable ref seems to be valid holding the value it was refering.

Code: Cpp
#include<iostream.h>

int main()
{
    int *ptr = new int;
    *ptr = 10;
   
    int &ref = *ptr;
   
    cout<<"Value of ref: "<<ref<<endl;
    cout<<"Value of *ptr: "<<*ptr<<endl;

    delete (ptr);
    ptr= NULL;
   
    cout<<"Value of ref: "<<ref<<endl;
    cout<<"Value of *ptr: "<<*ptr<<endl;
   
    return(0);
}

Value of ref: 10
Value of *ptr: 10
Value of ref: 10
Segmentation fault (core dumped)
0
technica's Avatar, Join Date: Dec 2007
CoderByNature
Good information. Good to read and thanks for sharing.
0
shabbir's Avatar, Join Date: Jul 2004
Go4Expert Founder
Nominate this article for Article of the month - Dec 2009
0
shabbir's Avatar, Join Date: Jul 2004
Go4Expert Founder
Vote for this article for Article of the Month - December 2009