Return by reference

A function can return by reference as shown below:

const int &getValue()
{
    static int value{5};
    return value;
}
 
int main(int argc, char const *argv[])
{
    const int &ref{getValue()};
    std::cout << ref << "\n";
 
    return 0;
}

static is used to make the variable to live until the end of the program. value’s reference is returned back from the function.

This is usually efficient when returning values which are expensive to copy. For example, returning a std::string or any other class object would lead to an expensive copy.

It is always necessary to keep in mind that the value which is being returned from the function should exist even after the function is completed, otherwise the reference would be dangling and accessing it would result in undefined behavior.

For example,

const int &getLiteral()
{
    return 5;
}
 
int main()
{
    std::cout << getLiteral() << "\n"; // it will most probably crash
    return 0;
}

Temporary object with value gets destroyed once the function completes and printing a dangling reference would lead undefined behavior.

Return by address

Returning by address is similar to reference. For example,

#include <iostream>
 
const int *getValue()
{
    static const int value{100};
    return &value;
}
int main(int argc, char const *argv[])
{
    const int *resultptr{getValue()};
    std::cout << *resultptr << "\n";
    return 0;
}

The advantage of return by address is that we can return nullptr when the function is nothing to return, that we couldn’t do with references.

However, the caller has to do a null pointer check before dereferencing the pointer.

References

  1. https://www.learncpp.com/cpp-tutorial/return-by-reference-and-return-by-address/