std::reference_wrapper around *this

std::reference_wrapper around *this

本文关键字:this around reference std wrapper      更新时间:2023-10-16

我有一个方案,我需要将*this链接到返回std::optional<std::reference_wrapper<T>>而不是T&而不是CC_3的函数(原因是此问题的范围不足)。我使用std::reference_wrapper的原因是因为std::optional无法进行参考,至少在C 11中不能进行参考。但是,这无效,因为我似乎遇到了终生问题。这是一个最小示例:

#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);
}

这将输出0 50而不是预期的42 50。如果我将其分为两个语句:

auto f = test();
auto f2 = f.foo();
bar(f2);

它可以按预期工作。使用调试器,我发现编译器正在优化某些表达式,而val则是不可初学的,这使我认为我在代码中具有不确定的行为。

我的行为不确定吗?如果是这样,我该如何避免在这里?

我的行为不确定吗?

是。auto从用于初始化它的表达式中推论对象的类型。然后,您使用类型std::reference_wrapper<test>的表达式来初始化f。临时test()在初始化f之后消失了,因此f立即悬挂。

您可以像已经这样做一样拆分声明,也可以使用std::references_wrappers的get成员函数:

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

无论哪种方式,std::reference_wrapper<test>都不是替换的下降,以便在所有情况下C 支持。代理对象永远不会。

我的行为不确定吗?

是。看看线auto f = test().foo();fstd::reference_wrapper<test>,它指的是test()test()的寿命在此行的末尾结束,您最终得到了悬空的参考。auto g = test().foo2();并非如此,因为它复制了返回值(感谢@storyteller在这里帮助我)。

我如何在这里避开它?

您需要从std::reference_wrapper零件中拆除寿命管理。这将有效:

test t;
auto f = t.foo();
// Do stuff with f until this scope ends.