Search⌘ K
AI Features

Discussion: What’s the Time of Death?

Understand the concept of temporary objects in C++ and how binding references can extend their lifetime. Learn why some temporary lifetimes end prematurely causing dangling references, and explore code examples illustrating these pitfalls. Discover rules governing lifetime extensions, common issues like those fixed in C++23, and practical recommendations to avoid subtle bugs by careful reference binding, staying updated with standards, and using tools like sanitizers. This lesson helps improve your grasp of C++ object lifetimes and writing reliable code.

Run the code

Now, it’s time to execute the code and observe the output.

C++ 17
#include <iostream>
struct MemoryArea
{
MemoryArea(int number) : number_(number) {}
~MemoryArea() { std::cout << "Freed memory area " << number_ << "\n"; }
int number_;
};
MemoryArea getMemory(int number) { return MemoryArea{number}; }
struct DataSource
{
DataSource(const MemoryArea &memoryArea)
: memoryArea_(memoryArea) {}
const MemoryArea &memoryArea_;
};
int main()
{
const auto &reference1 = getMemory(1);
std::cout << "Bound reference 1\n";
const auto &reference2 = getMemory(2).number_;
std::cout << "Bound reference 2\n";
const auto &reference3 = DataSource(getMemory(3));
std::cout << "Bound reference 3\n";
}

As we’ve seen a few times by now, a function call is a prvalue, and no object exists until that prvalue is used to initialize one. In the A Strange Assignment puzzle, we also saw an exception to this rule: when we didn’t use the prvalue to initialize an object, we called that a discarded-value expression and learned that a temporary is then materialized.

Understanding the output

In this puzzle, the results of the function call expressions aren’t assigned to objects as in the Counting Copies puzzle, but neither are they discarded as in the “A Strange Assignment” puzzle. Instead, we’re binding references to them in various ways. What happens then?

  • For the first call, we bind the reference reference1 directly to the prvalue. A temporary is materialized, as we briefly touched upon in the “A Strange Assignment” puzzle.

  • For the second call, we access the member number_ on a class prvalue. This is another case where a temporary needs to be materialized. Otherwise, no object would be there for us to access the member of.

  • For the third call, we pass the prvalue to ...