CS 70

When to Return References (and When Not To)

The advantages of using references for returning results are similar to those for passing arguments as references:

  • Returning a (non-const) reference lets you modify a pre-existing thing.
  • Returning a reference can save time by not needing to copy data around.

Pitfalls

What's wrong with the following code?

double& pi() {
    double val = 3.1415926535897931;
    return val;
}

Besides the fact that maybe we shouldn't return a value that can be modified for this particular function, what else is an issue?

What's wrong with this code?

Don't Return a Reference to a Local Variable!

We can see this issue in this slightly larger program:

#include <iostream>

// This function is fine.  It returns a reference to something that already
// existed outside the function.

double& changeToPi(double& changeMe) {
    changeMe = 3.1415926535897931;
    return changeMe;
}

// This function has a problem.  It returns a reference to a local variable.
// By the time the function returns, this value will have been destroyed and
// deallocated!

double& pi() {
    double val = 3.1415926535897931;
    return val;
}

int main() {
    double myDouble = 123.456;
    std::cout << "This is fine: " << changeToPi(myDouble) << std::endl;
    std::cout << "Uh oh, problem: " << pi() << std::endl;

    return 0;
}

If we compile this code in our Docker image, we get a compiler warning:

cs70 DOCKER > clang++ -O -o example example.cpp
example.cpp:14:12: warning: reference to stack memory associated with local variable 'val' returned [-Wreturn-stack-address]
    return val;
           ^~~
1 warning generated.
  • Horse speaking

    Hay! Wait a minute—you got a warning even though you didn't say all that -Wall -Wextra -pedantic stuff?

  • LHS Cow speaking

    That's right. Those options turn on a variety of helpful warnings, but this issue is so severe and so obviously a problem that the compiler issues a warning anyway.

  • Goat speaking

    Why isn't it an error, then?

  • Bjarne speaking

    Uh….

  • Goat speaking

    Yeah, I know, something-something-C++'s heritage. Meh.

  • LHS Cow speaking

    The main thing is, the compiler's warnings matter. Don't ignore them.

If we try running the program, it doesn't work properly:

cs70 DOCKER > ./passThruPi
This is fine: 3.14159
Uh oh, problem: 1.25548e+232

If you want to see why this problem happens, you could draw a memory diagram, or just watch the video below. (Or both!)

(When logged in, completion status appears here.)