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,
numberbecomes15. - Inside
main(),valuestill remains10.
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,
numberbecomes15. - Inside
main(),valuealso becomes15.
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
| Method | Syntax Example | Effect on Original Variable |
|---|---|---|
| Pass by value | void fun(int x) | No effect on original variable |
| Pass by reference | void 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
| Point | Pass by Value | Pass by Reference |
|---|---|---|
| Data sent to function | A copy of the argument | The original object through a reference |
| Changes affect caller | No | Yes |
| Copy cost | Can be expensive for large objects | Avoids full copy in many common cases |
| Safety from accidental modification | High | Lower unless const is used |
| Best use case | Small values or intentional copying | Modification 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
constwith 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
constreference 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.