Let's consider the following program:
#include <iostream>
#include <tuple>
using namespace std;
const int* f()
{
static int i = 5;
return &i;
}
int main()
{
auto [a] = std::forward_as_tuple( f() );
//auto&& [a] = std::forward_as_tuple( f() ); // same error
//const auto& [a] = std::forward_as_tuple( f() ); // same error
cout << *a << endl;
return 0;
}
I expect it to print 5
. I tried it on gcc 13.1 and MSVC 19.35, and it produces correct result when all optimizations are turned off. Anyway, when I add -O1 for gcc or /O2 for MSVC, the program starts crashing in runtime, and I can hardly understand why this happens. I found the following Note
on cppreference:
If the arguments are temporaries, forward_as_tuple does not extend their lifetime; they have to be used before the end of the full expression.
Is it the explanation? If so, can someone please elaborate what language rules am I violating in my code?
Following the trail that @NathanOliver had laid I managed to find an answer at cppreference:
a temporary bound to a reference parameter in a function call exists until the end of the full expression containing that function call: if the function returns a reference, which outlives the full expression, it becomes a dangling reference.
and
In general, the lifetime of a temporary cannot be further extended by "passing it on": a second reference, initialized from the reference variable or data member to which the temporary was bound, does not affect its lifetime.