Puzzle #6 (based on C++17)

#include <memory>

auto foo(int* ptr)
{
  *ptr = 2;
  return *ptr;
}

int main()
{
  return foo(std::make_unique<int>().get());
}

With given code and C++17 compiler, pick one answer:

  • Guaranteed to return 2 from main.
  • Guaranteed to return something other than 2 from main.
  • Undefined behavior.
  • Implementation defined.
  • Will not compile.
Click here for the answer

The correct answer is: Guaranteed to return 2 from main.

If you didn’t know this paragraph, you’ve probably gone with your intuition saying that after .get() call, unique pointer’s dtor is called, memory freed and ‘dangling’ pointer is passed to the function.
If you didn’t know this paragraph…

When an implementation introduces a temporary object of a class that has a non-trivial constructor ([class.ctor], [class.copy.ctor]), it shall ensure that a constructor is called for the temporary object. Similarly, the destructor shall be called for a temporary with a non-trivial destructor ([class.dtor]). Temporary objects are destroyed as the last step in evaluating the full-expression ([intro.execution]) that (lexically) contains the point where they were created. This is true even if that evaluation ends in throwing an exception. The value computations and side effects of destroying a temporary object are associated only with the full-expression, not with any specific subexpression.

Especially this part:

Temporary objects are destroyed as the last step in evaluating the full-expression ([intro.execution]) that (lexically) contains the point where they were created.

Thanks to that, unique_ptr lives for the whole function call, 2 is assigned and then returned from foo, to be finally returned from main.

Thanks for reading o/