在类中存储的闭包中通过引用捕获的临时的生命周期

Vit*_*meo 4 c++ lifetime language-lawyer temporary-objects c++17

请考虑以下代码段:

struct foo { };

template <typename F>
struct impl : F
{
    impl(F&& f) : F{std::move(f)} { }
    auto get() { return (*this)(); }
};

template <typename X>
auto returner(X&& x)
{
    return impl{[&x]{ return x; }};
//               ^~
}

int main()
{
    auto x = returner(foo{}).get();
}
Run Code Online (Sandbox Code Playgroud)

wandbox.org上的实例


  • 是否保证foo{}returner(foo{}).get()表达的整个过程中都会存活?

  • 或者只是foo{}为了活着returner(foo{}),因此在调用时会导致未定义的行为impl::get()


标准在[class.temporary]中说:

临时对象被破坏,作为评估(词法上)包含创建它们的点的完整表达式的最后一步.

[intro.execution]中

一个完整的表达是

  • 一个未评估的操作数,

  • 一个常数表达式,

  • init-declarator或mem-initializer,包括初始化程序的组成表达式,

  • 调用在临时对象([class.temporary])以外的对象的生命周期结束时生成的析构函数,或者

  • 一个表达式,它不是另一个表达式的子表达式,也不是完整表达式的一部分.

我不知道是否完全表达有关foo{}returner(foo{})returner(foo{}).get().

Bar*_*rry 10

这里重要的部分是:

全表达为[...]是不另一种表达的一个子表达式,这是不否则的一部分的表达全表达.

因此returner(foo{}).get(),returner(foo{})是表达式的子表达式returner(foo{}).get(),因此它不是完整表达式.因此:

是否保证foo{}returner(foo{}).get()表达的整个过程中都会存活?

是.

  • 速记99%准确的经验法则是"完全外向结束于`;`,或者可能有一个`;`并保持语义不变" (3认同)