如果存储原始参考的类不在范围之外,可以捕获会员参考安全吗?

Is it safe to capture a member reference if the class storing the original reference goes out of scope?

本文关键字:参考 安全 原始 存储 范围 如果      更新时间:2023-10-16

考虑以下内容:

#include <iostream>
#include <functional>
std::function<void()> task;
int x = 42;
struct Foo
{
   int& x;
   void bar()
   {
      task = [=]() { std::cout << x << 'n'; };
   }
};
int main()
{
   {
      Foo f{x};
      f.bar();
   }
   task();
}

我的本能是,由于执行任务时实际的指称仍然存在,因此我们在遇到lambda时获得了新的参考,并且一切都很好。

但是,在我的GCC 4.8.5(CentOS 7)上,我看到一些行为(在一个更复杂的程序中)表明这是UB,因为f和参考f.x本身已经死亡。是吗?

要捕获成员参考,您需要使用以下语法(在C 14中引入):

struct Foo
{
   int & m_x;
   void bar()
   {
      task = [&l_x = this->m_x]() { std::cout << l_x << 'n'; };
   }
};

这样的方式l_x是存储在闭合中的int &,指的是同一intm_x是引用的,并且不受Foo的影响。

在C 11中,我们可以通过对指针进行价值而丢失此功能:

struct Foo
{
   int & m_x;
   void bar()
   {
      int * p_x = &m_x;
      task = [=]() { std::cout << *p_x << 'n'; };
   }
};

您可以通过创建参考和显式捕获的本地副本来捕获C 11中的参考成员,以避免捕获this

void bar()
{
    decltype(x) rx = x; // Preserve reference-ness of x.
    static_assert(std::is_reference<decltype(rx)>::value, "rx must be a reference.");
    task = [&rx]() { std::cout << rx << ' ' << &rx << 'n'; }; // Only capture rx by reference.
}