Ch6.3: Passing Arguments

Overview

When you call a function, you pass arguments to its parameters. C++ provides several ways to pass arguments, each with different behavior and performance characteristics.

In this chapter, you will learn:

1. Pass‑by‑value

When you pass an argument by value, the function receives its own copy of the argument.


void increment(int x)
{
    ++x;   // modifies the copy
}

int main()
{
    int a{5};
    increment(a);
    // a is still 5
}

Pass‑by‑value is simple and safe, but copying large objects can be expensive.

2. Pass‑by‑reference (&)

When you pass an argument by reference, the function receives an alias to the original object. No copy is made.


void increment(int & x)
{
    ++x;   // modifies the original
}

int main()
{
    int a{5};
    increment(a);
    // a is now 6
}

Pass‑by‑reference allows the function to modify the caller’s variable.

3. Pass‑by‑const‑reference (T const &)

When you pass an argument by const reference, the function receives a reference to the original object, but cannot modify it.


void print_twice(::fast_io::string const & s)
{
    ::fast_io::println(s);
    ::fast_io::println(s);
}

This is ideal for large objects such as:

It avoids copying while guaranteeing that the function cannot change the data.

4. Why pass‑by‑value cannot modify the caller (swap example)

A classic example is a swap function. If you write it using pass‑by‑value, it will not work.


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

int main()
{
    int x{10};
    int y{20};

    bad_swap(x, y);
    // x is still 10, y is still 20
}

This fails because a and b are copies.

Correct swap using references


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

int main()
{
    int x{10};
    int y{20};

    good_swap(x, y);
    // x is now 20, y is now 10
}

Here, a and b refer to the original variables.

Swap using ::std::ranges::swap (preferred for objects)


#include <concepts>  // defines ::std::ranges::swap

int main()
{
    int x{10};
    int y{20};

    ::std::ranges::swap(x, y);

    // x is now 20, y is now 10
}

::std::ranges::swap is the modern, standard way to swap objects.

Swap using pointers and ::std::ranges::iter_swap

When you have pointers or iterators, use ::std::ranges::iter_swap.


#include <iterator>  // defines ::std::ranges::iter_swap

int main()
{
    int x{10};
    int y{20};

    int * px{::std::addressof(x)};
    int * py{::std::addressof(y)};

    ::std::ranges::iter_swap(px, py);  // swaps *px and *py

    // x is now 20, y is now 10
}

::std::ranges::iter_swap swaps the values pointed to by the iterators or pointers.

Where these functions are defined


#include <concepts>  // ::std::ranges::swap
#include <iterator>  // ::std::ranges::iter_swap

These headers provide the concepts and iterator utilities that power the ranges versions of swap.

5. When to use each method

Use pass‑by‑value when:

Use pass‑by‑reference when:

Use pass‑by‑const‑reference when:

These three forms cover almost all function parameter usage in modern C++.

Key takeaways