简体   繁体   English

std :: reference_wrapper围绕* this

[英]std::reference_wrapper around *this

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). 我有一个场景,我需要将一个可以被*this链接的函数转换为返回std::optional<std::reference_wrapper<T>>而不是T& (原因超出了这个问题的范围)。 The reason why I use std::reference_wrapper is since std::optional cannot take a reference, at least not in C++11. 我之所以使用std::reference_wrapper是因为std::optional不能引用,至少在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 . 这输出0 50而不是预期的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. 使用调试器,我发现编译器正在优化某些表达式并且val初始化,这使我认为我的代码中有未定义的行为。

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. auto从用于初始化它的表达式中推断出对象的类型。 And you use an expression of type std::reference_wrapper<test> to initialize f . 并使用std::reference_wrapper<test>类型的表达式来初始化f The temporary test() is gone after f is initialized, so f dangles immediately. f初始化后临时test()消失,因此f立即悬空。

You can either split the declaration as you do already, or use std::references_wrappers 's get member function: 你可以像你一样拆分声明,或者使用std::references_wrappers的get成员函数:

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. 无论哪种方式, std::reference_wrapper<test>都不是C ++支持的所有上下文中的引用替换。 Proxy objects never are. 代理对象永远不会。

Do I have undefined behavior? 我有未定义的行为吗?

Yes. 是。 Have a look at the line auto f = test().foo(); 看一下auto f = test().foo(); . f is a std::reference_wrapper<test> and the test instance it refers to is test() . fstd::reference_wrapper<test> ,它引用的test实例是test() The lifetime of test() ends right at the end of this line, and you end up with a dangling reference. test()的生命周期就在这一行的末尾结束,最后你会得到一个悬空参考。 That's not the case for auto g = test().foo2(); 对于auto g = test().foo2(); ,情况并非如此auto g = test().foo2(); as it copies the return value (thanks to @StoryTeller for helping me out here). 因为它复制了返回值(感谢@StoryTeller帮助我这里)。

how do I avoid it here? 我怎么在这里避免它?

You need to tear apart lifetime management from the std::reference_wrapper part. 您需要从std::reference_wrapper部分拆除生命周期管理。 This will work: 这将有效:

test t;
auto f = t.foo();

// Do stuff with f until this scope ends.

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM