I have a scenario where I need to convert a function that can be chained by *this
to returning std::optional<std::reference_wrapper<T>>
instead of T&
(reason is out of scope for this question). The reason why I use std::reference_wrapper
is since std::optional
cannot take a reference, at least not in C++11. However, that doesn't work because I seem to be encountering lifetime issues. Here is a minimal example:
#include <iostream>
#include <functional>
struct test {
std::reference_wrapper<test> foo() {
val = 42;
return *this;
}
test& foo2() {
val = 50;
return *this;
}
int val;
};
void bar(test t) {
std::cout << std::move(t).val << "\n";
}
int main()
{
auto f = test().foo();
bar(f);
auto g = test().foo2();
bar(g);
}
This outputs 0 50
instead of the expected 42 50
. If I split it up into two statements:
auto f = test();
auto f2 = f.foo();
bar(f2);
It works as expected. Using the debugger, I discover that the compiler is optimizing some of the expression away and val
is left uninitialized, which leads me to think I have undefined behavior in my code.
Do I have undefined behavior? If so, how do I avoid it here?
Do I have undefined behavior?
Yes. auto
deduces the type of the object from the expression used to initialize it. And you use an expression of type std::reference_wrapper<test>
to initialize f
. The temporary test()
is gone after f
is initialized, so f
dangles immediately.
You can either split the declaration as you do already, or use std::references_wrappers
's get member function:
auto f = test().foo().get();
Either way, std::reference_wrapper<test>
is not a drop in replacement for a reference in all contexts C++ supports. Proxy objects never are.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With