Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

std::reference_wrapper around *this

Tags:

c++

c++11

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?

like image 999
user11164696 Avatar asked Jan 26 '23 15:01

user11164696


1 Answers

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.

like image 72
StoryTeller - Unslander Monica Avatar answered Feb 08 '23 08:02

StoryTeller - Unslander Monica