Search

8.10 — Return by reference and return by address

In previous lessons, we discussed that when passing an argument by value, a copy of the argument is made into the function parameter. Copying fundamental types is cheap, so this fine. But copying is typically expensive for class types (such as std::string), and we can avoid paying this cost by passing by (const) reference instead.

We encounter a similar situation when returning by value: a copy of the return value is returned to the caller. If the return type of the function is a class type, this can be expensive.

In such cases, we may (or may not) want to return by reference instead. Return by reference returns a reference that is bound to the object being returned, which avoids making a copy of the return value. To return by reference, we simply define the return value of the function to be a reference type:

Here is a trivial program to demonstrate a value returned by reference:

When getProgramName() is called, it returns programName. Because the return type of this function is a const reference, the function returns a const reference to programName. That const reference can then be used to access the value of programName, which is printed.

The object being returned by reference must exist after the function returns

Using return by reference has one major caveat: the programmer must be sure that the object being referenced outlives the function returning the reference. Otherwise, a dangling reference will be returned, and undefined behavior will result.

In the program above, because programName is a global variable, it will exist until the end of the program, so the reference returned by getProgramName will still be valid even after getProgramName() returns.

Let's see an example of a case where this is not true. Consider the following example that returns a local variable by reference:

What's the result of this program? It's indeterminate. When someFunction() returns, a reference bound to local variable s is returned. Then, because s is an automatic variable, s is destroyed at the end of the function. The means the returned reference is now dangling, and any use of the reference will result in undefined behavior.

Modern compilers will produce a compile error if you try to return a local variable by reference (so the above program won't even compile), but compilers sometimes have trouble detecting more complicated cases.

Warning

Objects returned by reference must live beyond the scope of the function returning the reference, or a dangling reference will result. Never return a local variable by reference.

Typically, references are returned in one of two cases:
* The return type is a class object

1) When returning a parameter passed in by reference:

In the above function, the caller must pass in valid objects for a and b, therefore it's safe to return a or b, as those objects will still exist in the scope of the caller when the function returns.

2) When returning an object from a collection of objects that persists beyond the scope of the function.

For example, let's say we have a list of monster objects for some dungeon crawler game we're writing. If we write a function to get a monster from the list, we don't need to return a copy -- we can just return a reference to the object in the list.

. For example, let's say we have a list of the names of students in a class. We could write a function to return the nth name on the list. Rather than returning a copy of the name, we could return a reference to the name,

class object that is otherwise guaranteed to exist beyond the scope of the function. For example, if we have a list of objects representing students, we

When an accessor member function of a class is returning a class member (we'll cover this case in future lesson 8.4 -- Access functions and encapsulation when we talk about creating your own class types).

Chaining function calls

Return by address

Return by address works almost identically to return by reference (covered in lesson %Failed lesson reference, id XX%), except a pointer is returned instead of a reference. Return by address has the same caveats as return by reference -- the object being returned must outlive the scope of the function, otherwise the caller will receive a dangling pointer.

Return by address is typically only used in two situations:

  1. When returning a parameter passed in by address
  2. When returning a member pointer from a class object (we'll cover this in a future lesson)

For advanced readers

Readers who are familiar with dynamically allocated memory (covered in chapter 9) might wonder why returning dynamically allocated memory from a function isn't included on the above list. While legacy code often does so, this can lead to ownership challenges. Returning a smart pointer (covered in chapter M) is a better choice in such situations.

Return by address

Return by address works almost identically to return by reference (covered in lesson %Failed lesson reference, id XX%), except a pointer is returned instead of a reference. Return by address has the same major caveat as return by reference -- the object being returned must outlive the scope of the function, otherwise the caller will receive a dangling pointer.

The major advantage of return by address over return by reference is that we can have the function return nullptr if there is no valid object found to return. For example, let's say we have a list of students that we want to search. If we find the student we are looking for in the list, we can return a pointer to the object representing the matching student. If we don't find any students matching, we can return nullptr to indicate a matching student object was not found.

If returning "no object" is not needed, return by reference should be preferred.

The major disadvantage of return by address is that the caller has to remember to do a nullptr check before dereferencing the return value, otherwise a null pointer dereference may occur and undefined behavior will result. It's also significantly easier to return a dangling pointer than a dangling reference due to the ability to repoint pointers.


8.11 -- In and out parameters
Index
8.9 -- Pass by address

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="">