How do I  

Chapter 8: References, Call by Value vs. Call by Reference

Previous chapter: Chapter 7: Pointers and Memory Management in C++

Building on the concept of memory addresses, this chapter explores references and the critical distinction in C++ functions between passing data by value (copy) and passing data by reference (alias).

1. References: Aliases for Variables

A reference is a second name, or an alias, for an existing variable. Once initialized, a reference acts exactly like the variable it refers to. Unlike pointers, a reference cannot be changed to refer to a different variable later, and it cannot be null.

Declaring a Reference

You declare a reference by placing the address-of operator (&) after the data type.

int original_score = 95;
int& alias_score = original_score; // alias_score is a reference to original_score

// Changing the reference changes the original variable
alias_score = 100;

std::cout << "Original score: " << original_score << std::endl; // Output: 100

In many ways, a reference provides the power of a pointer (working directly with the original memory) without the complex syntax of the dereference operator (*).

2. Parameter Passing: Call by Value

When an argument is passed to a function using call by value, a separate, temporary copy of the argument's data is created within the function's scope.

Effect: Any changes made to the parameter inside the function are applied only to the copy and do not affect the original variable outside the function.

void increment_value(int num) {
    num++; // Only the copy is incremented
}

int main() {
    int x = 5;
    increment_value(x);
    // x remains 5 outside the function
    return 0;
}

3. Parameter Passing: Call by Reference

To allow a function to modify the original variable, you must use call by reference. This can be achieved in two ways:

A. Reference Parameters (The C++ Way)

This is the cleanest and safest way. You pass the function a reference to the original variable.

void increment_reference(int& num) {
    num++; // The original variable is incremented
}

int main() {
    int x = 5;
    increment_reference(x);
    // x is now 6
    return 0;
}

B. Pointer Parameters (The C Way)

You pass the function a pointer (the memory address) to the original variable, and then dereference the pointer inside the function to change the value.

void increment_pointer(int* num_ptr) {
    (*num_ptr)++; // Dereference and increment the original value
}

4. const References: Efficiency and Safety

When passing large objects (like a custom class or a large std::string) to a function, copying the object (call by value) is inefficient. However, if the function doesn't need to change the object, you can pass it as a const reference.

// Passes the address (efficient) but prevents modification (safe)
void print_string(const std::string& text) {
    std::cout << text << std::endl;
    // text += " cannot modify!"; // ERROR: const prevents changes
}

This pattern is widely used in C++ for performance gains without sacrificing data integrity.