C++ - c++ function - C++ Pass by reference

C++ Pass By Reference Explained

In C++, you may need to allow a function to access one of its parameters directly without creating a copy. You may be passing a complex data structure as a parameter, or you could be looking to optimize the function’s performance on a very large number of function calls.

One way to achieve such access is to use “pass by reference.” In this guide, we’ll show you how to implement pass by reference and discuss when it makes the most sense to do so.

What Is Pass by Reference?

Pass by reference is something that C++ developers use to allow a function to modify a variable without having to create a copy of it. To pass a variable by reference, we have to declare function parameters as references and not normal variables.

Let’s see this in action:

#include <iostream>
using namespace std;

void duplicate(int& b)
{     b*=2;
}

int main()
{
    int x = 25;
    cout << "The original value of x is " << x << endl;
    duplicate(x);
    cout << "The new value of x is " << x;
    return 0;
}

We’ll break this code down in a bit, but let’s first take a look at the differences between an argument and a parameter. 

Arguments and Parameters

Although similar, arguments and parameters have different uses in code.

When you call upon a function, the values that get passed are known as arguments. The function sends the values of the arguments to the receiving function to take the place of parameters.

Parameters, on the other hand, are a formal way to show a placeholder for a variable in a function. They are used in the function itself and are assigned values based on arguments when the function is called.

Take a look at this example:

//More code

Function CalcKilograms (Real Pounds)
    Declare Real Kilograms
   
    Assign Kilograms = (Pounds*2.2)
Return Real Kilograms

//More code

If the CalcKilograms function is called passing in the value 100, as in CalcKilograms(100), the argument is 100 and the parameter is Pounds.

How Does Pass By Reference Work With Functions?

Let’s take another look at our original example:

#include <iostream>
using namespace std;

void duplicate(int& b)
{
    b*=2;
}

int main()
{
    int x = 25;
    cout << "The original value of x is " << x << endl;
    duplicate(x);
    cout << "The new value of x is " << x;
    return 0;
}

If you recall, using pass by reference allows us to effectively “pass” the reference of a variable in the calling function to whatever is in the function being called. The called function gets the ability to modify the value of the argument by passing in its reference. This replaces the original argument before the parameters reference it.

In our program above, we have a pretty basic main function. This function first declares variable “x” to be 25 and then outputs that value. After that, we introduce a new function, duplicate, and then want to output the new value of “x.” This duplicate function is the key to using pass by reference to make changes to our argument “x.”

void duplicate(int& b) becomes our pass by reference. In our duplicate function, (int& b) creates variable “b” as a copy of “x,” referencing its value. The duplicate function performs the operator on “b,” and then replaces the value of “x” with the new value of “b.”

We get the following as a result:

  • The original value of “x” is 25;
  • The new value of “x” is 50.

This shows that the program returns the original value of “x” before the duplicate function, and then outputs the value of “x” after the pass by reference.

When Is Pass by Reference Most Useful?

Pass by reference serves key purposes in C++ code. Let’s take a look at when this technique is beneficial to use.

Modifying Local Variables of the Caller Function

As we saw above, we can use pass by reference to modify local variables of a function. When you call a function that needs to modify arguments, pass by reference is the only way to accomplish this task.

Passing Large-Sized Arguments

If an argument is significant in size (like a string that’s a list), it makes more sense to use pass by reference to avoid having to move the entire string. Effectively, pass by reference will pass just the address of the argument and not the argument itself. The example below is inefficient because a new number would create a copy of all data members.

// More code here

class ClientNumber{
private:
    string name;
    string number;

// More code here
};

void printNumber(ClientNumber num)
{
    cout << num.getName();
    cout << num.getNumber();

// More code here
}

By transforming ClientNumber into a reference, we can prevent that from happening and make our program more efficient. From a coding standpoint, it’s as simple as adding in an ampersand:

// More code here

class ClientNumber{
private:
    string name;
    string number;

// More code here
};

void printNumber(ClientNumber& num)
{
    cout << num.getName();
    cout << num.getNumber();

// More code here
}

Polymorphism in a Function

It’s possible to use pass by reference to make a function polymorphic by passing objects to it. In the example below, due to the reference in the core class, display() calls the core function show() if core is passed, and the alternate function show() if the alt object is passed.

#include <iostream>
using namespace std;

class core {
public:
    virtual void show()
    {
        cout << "Core \n";
    }
};

class alt: public core {
public:
    void show() { cout << "Alternate \n"; }
};

void display(core& c) { c.show(); }

int main(void)
{
    core c;
    alt a;
    display(c);
    display(a);
    return 0;
}

The program returns the following:

Core
Alt

Alternatives to Pass By Reference

Within C++ there are two other options for passing arguments, each with their subtle differences.

Pass By Value

With pass by value, local parameters become copies of the original arguments that are passed in. Therefore, changes made in the function to the passed arguments do not affect the originals. Here’s a use of pass by value in comparison to our pass by reference example:

#include <iostream>
using namespace std;

void duplicate(int b)
{
    b*=2;
}

int main()
{
    int x = 25;
    cout << "The original value of x is " << x << endl;
    duplicate(x);
    cout << "The new value of x is " << x;
    return 0;
}

In both cases, the output for “x” is the same because changes to the arguments passed into the duplicate function do not affect the original arguments, which remain the same.

  • The original value of “x” is 25;
  • The new value of “x” is 25.

Pass By Pointer

Pass by pointer works even more similarly to pass by reference and even achieves the same result:

#include <iostream>
using namespace std;

void duplicate(int* b)
{
    *b*=2;
}

int main()
{
    int x = 25;
    cout << "The original value of x is " << x << endl;
    duplicate(&x);
    cout << "The new value of x is " << x;
    return 0;
}
  • The original value of “x” is 25;
  • The new value of “x” is 50.

The key differences between pass by reference and pass by pointer lie in the fact that a pointer can store the address of any variable to a location in the memory. It’s also possible to not initialize a pointer and instead assign it to null.

Reference, on the other hand, always references a variable and shares a memory location with it. Changing the original variable also changes the reference variable. Also, it’s not possible to reassign a reference.

Learn C++ Online

Knowing how to use pass by reference with functions is integral to programming in C++. 

Want to become a C++ developer? Check out our specialized C++ Nanodegree, where you’ll learn the language from industry experts by coding five projects of your own.

Enroll in our C++ Nanodegree program today!

<p><a class="btn btn-primary" href="https://www.udacity.com/course/c-plus-plus-nanodegree--nd213" target="blank" rel="noopener noreferrer">Start Learning</a></p>