Of course, an rvalue reference is still a reference so it can be dangling as well. You just have to bring the compiler into a situation where he has to drag the reference along and at the same time you just escape the refered-to value's scope, like this:
Demo
#include <cstdio>
#include <tuple>
std::tuple<int&&> mytuple{ 2 };
auto pollute_stack()
{
printf("Dumdudelei!\n");
}
int main()
{
{
int a = 5;
mytuple = std::forward_as_tuple<int&&>(std::move(a));
}
pollute_stack();
int b = std::get<int&&>(mytuple);
printf("Hello b = %d!\n", b);
}
Output:
Dumdudelei!
Hello b = 0!
As you can see, b now has the wrong value. How come? We stuffed an rvalue reference to an automatic variable a
into a global tuple. Then we escaped the scope of a
and retrieve its value through std::get<int&&
> which will evaluate to an rvalue-reference. So the new object b is actually move constructed from a
, but the compiler doesn't find a
because its scope has ended already. Therefore std::get<int&&>
evaluates to 0 (although it is probably UB and could evaluate to anything).
Note that if we don't touch the stack, the rvalue reference will actually still find the original value of object a
even after its scope has ended and will retrieve the right value (just try it and uncomment pollute_stack()
and see what happens). The pollute_stack()
function just moves the stack pointer forward and back while writing values to the stack by doing some io-related stuff through printf()
.
The compiler doesn't see through this though at all so be aware of this.