Parameter Passing Mechanisms in C++: Value, Pointer, and Reference Semantics
A reference in C++ creates an alternative name for an existing object. Once established, it acts as an alias for the target variable, sharing the same memory address and value. Unlike pointers, references must be initialized at declaration and cannot be rebound to different objects afterward.
#include <iostream>
int main() {
int original = 42;
int &alias = original; // Reference initialization required
// int &unbound; // Error: references must be initialized
// int &alias = other; // Error: cannot rebind existing reference
int another = 100;
alias = another; // Assigns value to original, not rebinding
std::cout << original << std::endl; // Outputs 100
return 0;
}
When passing arguments to functions, C++ offers three distinct mechanisms. Consider ecxhanging two integer values:
#include <iostream>
// Pass-by-value: operates on copies
void exchangeValues(int first, int second) {
int buffer = first;
first = second;
second = buffer;
}
// Pass-by-pointer: operates via memory addresses
void exchangePointers(int* ptr1, int* ptr2) {
int buffer = *ptr1;
*ptr1 = *ptr2;
*ptr2 = buffer;
}
// Pass-by-reference: operates directly on originals
void exchangeReferences(int& ref1, int& ref2) {
int buffer = ref1;
ref1 = ref2;
ref2 = buffer;
}
int main() {
int x = 10, y = 20;
exchangeValues(x, y);
// x and y remain unchanged
exchangePointers(&x, &y);
// x and y are now swapped
int m = 5, n = 15;
exchangeReferences(m, n);
// m and n are swapped without address-of operator
return 0;
}
References can also serve as function return types, enabling chained assignments and persistent access to data:
#include <iostream>
int& retrieveStatic() {
static int persistent = 50;
return persistent;
}
int main() {
int& proxy = retrieveStatic();
std::cout << proxy << std::endl; // 50
retrieveStatic() = 200; // Function as lvalue
std::cout << proxy << std::endl; // 200
return 0;
}
For safety against uinntended modifications, use const references. They prevent the function from altering the source data and extend object lifetimes when binding to temporaries:
#include <iostream>
void display(const int& data) {
// data = 999; // Compilation error: assignment of read-only reference
std::cout << data << std::endl;
}
int main() {
int value = 88;
display(value);
const int& literalRef = 42; // Binds to temporary
std::cout << literalRef << std::endl;
return 0;
}