Difference between const reference and normal parameter

void DoWork(int n);
void DoWork(const int &n);

What's the difference?


The important difference is that when passing by const reference, no new object is created. In the function body, the parameter is effectively an alias for the object passed in.

Because the reference is a const reference the function body cannot directly change the value of that object. This has a similar property to passing by value where the function body also cannot change the value of the object that was passed in, in this case because the parameter is a copy.

There are crucial differences. If the parameter is a const reference, but the object passed it was not in fact const then the value of the object may be changed during the function call itself.

E.g.

int a;

void DoWork(const int &n)
{
    a = n * 2;  // If n was a reference to a, n will have been doubled 

    f();  // Might change the value of whatever n refers to 
}

int main()
{
    DoWork(a);
}

Also if the object passed in was not actually const then the function could (even if it is ill advised) change its value with a cast.

e.g.

void DoWork(const int &n)
{
    const_cast<int&>(n) = 22;
}

This would cause undefined behaviour if the object passed in was actually const.

When the parameter is passed by const reference, extra costs include dereferencing, worse object locality, fewer opportunities for compile optimizing.

When the parameter is passed by value an extra cost is the need to create a parameter copy. Typically this is only of concern when the object type is large.


The difference is more prominent when you are passing a big struct/class:

struct MyData {
    int a,b,c,d,e,f,g,h;
    long array[1234];
};
void DoWork(MyData md);
void DoWork(const MyData& md);

When you use use 'normal' parameter, you pass the parameter by value and hence creating a copy of the parameter you pass. If you are using const reference, you pass it by reference and the original data is not copied.

In both cases, the original data cannot be modified from inside the function.


EDIT:
In certain cases, the original data might be able to get modified as pointed out by Charles Bailey in his answer.


There are three methods you can pass values in the function

  1. Pass by value

    void f(int n){
        n = n + 10;
    }
    
    int main(){
        int x = 3;
        f(x);
        cout << x << endl;
    }
    

    Output: 3. Disadvantage: When parameter x pass through f function then compiler creates a copy in memory in of x. So wastage of memory.

  2. Pass by reference

    void f(int& n){
        n = n + 10;
    }
    
    int main(){
        int x = 3;
        f(x);
        cout << x << endl;
    }
    

    Output: 13. It eliminate pass by value disadvantage, but if programmer do not want to change the value then use constant reference

  3. Constant reference

    void f(const int& n){
        n = n + 10; // Error: assignment of read-only reference  ā€˜nā€™
    }
    
    int main(){
        int x = 3;
        f(x);
        cout << x << endl;
    }
    

    Output: Throw error at n = n + 10 because when we pass const reference parameter argument then it is read-only parameter, you cannot change value of n.


With

 void DoWork(int n);

n is a copy of the value of the actual parameter, and it is legal to change the value of n within the function. With

void DoWork(const int &n);

n is a reference to the actual parameter, and it is not legal to change its value.