Search

8.9 — Pass by address

In prior lessons, we’ve covered pass by value (2.3 -- Introduction to function parameters and arguments) and pass by reference (8.5 -- Pass by reference). Pass by value allows us to pass a copy of an argument to the function. Because the function parameter receives a copy of the argument, any changes made to the parameter are not made to the argument. Pass by reference allows us to pass a reference to the argument to the function. This avoids making a copy of the argument, and (if the reference is non-const) also allows the function to change the value of the argument.

C++ provides a third way to pass values to a function, called pass by address. Pass by address involves passing the address of an argument to the function by using a pointer parameter.

Here is an example of a function that takes a parameter passed by address:

This prints:

55

In the above program, the main() function passes the address of x to function print(), which then uses the dereference operator (*) to get the value at that address for printing. Note that we can pass either a pointer (assuming we have one), or use the address-of operator (&) to get a pointer to the address of a normal variable.

Pass by address does not make a copy of the argument

Much like pass by reference, when we pass an argument by address, no copy of the argument is made. Instead, we’re passing a copy of the argument’s address to the function (which is fast).

Here’s an example showing a std::string passed by value, by reference, and by address:

Because copying a std::string is expensive (it’s a compound type, not a fundamental type), we want to pass it by reference or by address to avoid making a copy when the function is called.

Pass by address allows the function to modify the argument’s value

Also much like pass by reference, when we pass an argument by address, the function can modify the argument via the pointer parameter:

This prints:

5
6

As you can see, the argument is modified and this modification persists even after changeValue() has finished running.

Pass by address allows passing optional or null parameters

HERE HERE

Let’s say you’re writing a function that has a parameter that may or may not exist (CLARIFY)

// show example with just value or reference
// show why pass by address is better

Here’s a more fully fleshed out (but less practical) example using std::string:

The above program prints:

Your name is Alex
Your name is unknown

Null checking

Now consider this fairly innocent looking program:

When this program is run, it will print the value 5 and then most likely crash.

In the second call to print(), we’re passing a nullptr value, which makes parameter ptr a null pointer. When this null pointer is dereferenced in the body of print(), undefined behavior results.

When passing a parameter by address, care should be taken to ensure the pointer is not a null pointer before you dereference the value.

One way to do that is to use a conditional statement:

If a null pointer should never be passed to the function, an assert (which we covered in lesson 8.2 -- Introduction to unscoped enumerations) may be a better choice (as it explicitly documents that a null pointer is an invalid value):

Rule

All function parameters passed by pointer should be checked for null values (via a conditional statement or assert) before dereferencing them.

Passing by pointer to const

In the case of the print() function from the prior example, since the function does not modify the value being pointed to, we really should make the function parameter a pointer to const:

This allows us to tell at a glance that print() won’t modify the argument passed in, and will ensure that we don’t do so by accident.

Prefer pass by reference

Note that function print in the example above doesn’t handle null values very well -- it effectively just aborts the function. Given this, why allow a user to pass in a null value at all? Unless a function needs to handle both normal and null values, pass by reference is generally preferable to pass by address because references don’t allow null values.

Best practice

Prefer pass by reference to pass by address unless your function needs to handle null values or the ability to repoint at another address.

Changing what a pointer parameter points at

When we pass an address to a function, that address is copied from the argument into the pointer parameter (which is fine, because copying an address is fast). As shown in the initial example, we can dereference that address to have the function change the value of the argument.

However, what if we instead change the address held by the parameter (e.g. repoint the parameter at something else)? The following program explores this:

This program prints:

ptr is non-null
ptr is non-null

As you can see, changing the address held by the pointer parameter had no impact on the address held by the argument (ptr still points at x).

If you think about it, this makes sense. When function nullify() is called, ptr2 is instantiated as its own pointer object, and then initialized with the address passed in (in this case, the address held by ptr, which is the address of x). When the function changes what ptr2 points at, this only affects the ptr2 object, not the argument.

So what if we want to allow a function to change what a pointer argument points to?

Pass by pointer… by reference?

Yup, it’s a thing. Just like we can pass a normal variable by reference, we can also pass pointers by reference. Here’s the same program as above now with ptr2 changed to be a reference to an address:

This program prints:

ptr is non-null
ptr is null

When an argument is passed as a reference to a pointer, any changes made to the function parameter (which is a reference) are reflected through to the argument. This allows functions to “repoint” an argument. We can see in the program above that the nullify function is able to point ptr2 to null, which because ptr2 is a reference to ptr, changes what ptr points to.

As an aside...

Because references to pointers are fairly uncommon, it can be easy to mix up the syntax for a pointer to reference (is it “int*&” or “int&*”?). The good news is that if you do it backwards, the compiler will error that you can’t have a pointer to a reference (because pointers must hold the address of an object, and references aren’t objects). Then you can switch it around.


8.10 -- Return by reference and return by address
Index
8.8 -- Pointers and const

Leave a Reply

You can use these HTML tags

<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code class="" title="" data-url=""> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong> <pre class="" title="" data-url=""> <span class="" title="" data-url="">