Pass by Value and Pass by Reference in C++

Pass by value and pass by reference in C++ describe how arguments are sent to a function. This is one of the most important topics in C++ because it directly affects correctness, performance, and whether the original variable can be modified by the function. If this topic is not understood clearly, many function-related bugs become hard to detect.

When a value is passed to a function, C++ can either send a copy of the original data or allow the function to work with the original object itself. These two approaches are called pass by value and pass by reference. They may look similar at the call site, but their behavior inside the function is very different.

What Is Pass by Value in C++?

In pass by value, the function receives a copy of the argument. The original variable and the function parameter are two separate objects. Any change made to the parameter inside the function affects only the copy, not the original variable in the calling code.

This method is simple and safe when the function only needs to read a small value or when you intentionally want to protect the original data from modification. Primitive types such as int, char, and double are often passed by value because copying them is cheap.

void showValue(int x)
{
    x = x + 10;
}

In this function, x is only a copy. If the original variable had the value 5, and the function adds 10 to x, the original variable outside the function remains unchanged.

Example of Pass by Value in C++

#include <iostream>
using namespace std;

void increase(int number)
{
    number = number + 5;
    cout << "Inside function: " << number << endl;
}

int main()
{
    int value = 10;
    increase(value);
    cout << "Inside main: " << value << endl;
    return 0;
}

Output explanation:

  • Inside the function, number becomes 15.
  • Inside main(), value still remains 10.

This clearly shows that pass by value creates an independent copy. The function can work with that copy, but the original argument remains unchanged.

What Is Pass by Reference in C++?

In pass by reference, the function parameter becomes another name for the original argument. This means the function does not work with a copy. It works with the actual variable that was passed from the calling code. If the function changes the reference parameter, the original variable also changes.

Pass by reference is useful when a function needs to modify the caller’s data or when copying an object would be expensive. In C++, a reference parameter is written using the & symbol in the parameter list.

void showReference(int &x)
{
    x = x + 10;
}

Here, x refers to the original argument. If the caller passes a variable with the value 5, and the function adds 10, the caller’s variable becomes 15.

Example of Pass by Reference in C++

#include <iostream>
using namespace std;

void increase(int &number)
{
    number = number + 5;
    cout << "Inside function: " << number << endl;
}

int main()
{
    int value = 10;
    increase(value);
    cout << "Inside main: " << value << endl;
    return 0;
}

Output explanation:

  • Inside the function, number becomes 15.
  • Inside main(), value also becomes 15.

This happens because number is not a copy. It directly refers to the original variable value.

Syntax Difference Between Pass by Value and Pass by Reference

MethodSyntax ExampleEffect on Original Variable
Pass by valuevoid fun(int x)No effect on original variable
Pass by referencevoid fun(int &x)Changes affect original variable

The visual difference is small, but the effect is major. The & in the parameter list tells the compiler that the function parameter should bind to the original object instead of receiving a copy.

How Memory Behavior Differs

Pass by value usually creates a separate storage location for the function parameter. The function works with its own local copy, so modifications stay local. Pass by reference does not create that independent copy for normal use. The parameter refers to the same underlying object that exists in the calling scope.

This difference matters more when working with large objects. Copying a small integer is cheap, but copying a large string, vector, or custom object may take more time and memory. That is one reason reference parameters are common in modern C++ code.

Pass by Value vs Pass by Reference in Swapping

Swapping two variables is a classic example that clearly shows why references matter. If we try to swap using pass by value, only local copies change. If we swap using pass by reference, the real variables in the caller are exchanged.

#include <iostream>
using namespace std;

void swapByValue(int a, int b)
{
    int temp = a;
    a = b;
    b = temp;
}

void swapByReference(int &a, int &b)
{
    int temp = a;
    a = b;
    b = temp;
}

int main()
{
    int x = 10, y = 20;

    swapByValue(x, y);
    cout << "After swapByValue: " << x << " " << y << endl;

    swapByReference(x, y);
    cout << "After swapByReference: " << x << " " << y << endl;

    return 0;
}

After swapByValue(), the values of x and y remain unchanged. After swapByReference(), the actual values in main() are swapped. This is one of the clearest practical demonstrations of reference parameters.

When to Use Pass by Value in C++

  • When the data type is small and cheap to copy.
  • When the function should not modify the original variable.
  • When you want complete isolation between the function parameter and the caller’s data.
  • When copying is part of the intended logic.

Pass by value is often the easiest choice for small numeric types and simple logic. It keeps side effects under control because the original variable cannot be changed accidentally through the parameter.

When to Use Pass by Reference in C++

  • When the function needs to modify the original variable.
  • When the object is large and copying would be expensive.
  • When you want to avoid unnecessary copies for efficiency.
  • When a function must return multiple results through parameters.

Reference parameters are widely used with user-defined types, standard library containers, and large strings. They allow the function to work efficiently while still using natural function-call syntax.

What About const Reference in C++?

There is an important middle ground in C++ called pass by const reference. In this approach, the function receives a reference to the original object, but the object cannot be modified through that reference. This gives two benefits at the same time: no expensive copy, and no accidental modification.

#include <iostream>
#include <string>
using namespace std;

void printName(const string &name)
{
    cout << name << endl;
}

This style is very common in real C++ programs. It is especially useful for large objects that only need to be read, not changed. Many professional C++ codebases prefer const T& for read-only parameters of non-trivial types.

Using Reference Parameters for Multiple Outputs

Reference parameters are also useful when a function needs to send back more than one result. A function can return one main value directly and still update additional values through reference parameters, or it can return all results through references if that matches the design. This pattern appears in parsing, searching, and mathematical helper functions where several related results must be produced together.

Pass by value cannot do this because changes to value parameters stay inside the function. Reference parameters make the result visible to the caller immediately. Even so, this technique should be used carefully. If too many outputs are pushed through references, the function becomes harder to read, so the interface should stay clear and intentional.

Comparison Table: Pass by Value vs Pass by Reference

PointPass by ValuePass by Reference
Data sent to functionA copy of the argumentThe original object through a reference
Changes affect callerNoYes
Copy costCan be expensive for large objectsAvoids full copy in many common cases
Safety from accidental modificationHighLower unless const is used
Best use caseSmall values or intentional copyingModification or efficient access to large objects

Common Mistakes with Pass by Value and Reference

  • Expecting pass by value to modify the original variable.
  • Using pass by reference when the function should not change the data.
  • Forgetting to use const with read-only reference parameters.
  • Copying large objects unnecessarily by passing them by value.
  • Confusing reference parameters with pointers.

One common beginner mistake is writing a function that looks like it should swap or update the caller’s values, but the parameters are passed by value, so the original data never changes. Another mistake is overusing non-const references, which can make functions harder to reason about because the caller cannot easily tell what may be modified.

References vs Pointers in Function Parameters

References and pointers can both be used to let a function access caller-owned data, but they are not the same. A reference must refer to a valid object after binding, and normal use does not require dereferencing syntax. A pointer stores an address and must be dereferenced explicitly using *. Pointers can also be nullptr, while ordinary references do not work that way.

For simple parameter passing where a valid object is required, references often give cleaner syntax and clearer intent. Pointers are more appropriate when nullability, manual address handling, or reseating behavior is part of the design.

Best Practices for Function Parameters in C++

  • Use pass by value for small built-in types when copying is cheap.
  • Use pass by reference when the function must modify the caller’s object.
  • Use const reference for large objects that should not be changed.
  • Be explicit about side effects in function design.
  • Choose the simplest parameter style that correctly expresses intent.

Good C++ code is not only about making the program work. It is also about making intent obvious. Choosing between pass by value, pass by reference, and const reference is part of that clarity. When the parameter style matches the function’s real purpose, the code becomes easier to read, safer to use, and more efficient in practice.


Continue learning C++ in order
Follow the topic sequence with the previous and next lesson.