存储在容器中的C++ Lambda捕获"this"

Spa*_*nol 2 c++ lambda c++11

考虑以下最小代码:

#include <functional>
#include <iostream>
#include <string>
#include <vector>

class A
{
public:
  A() :
    s("dummy"),
    f([&, this]{ return s == "dummy"; }),
  {}
  std::string s;
  std::function<bool ()> f;
};

int main(int argc, char *argv[])
{
  A a;
  a.f(); // seems fine

  std::vector<A> as({});
  as[0].f(); // segmentation fault
}
Run Code Online (Sandbox Code Playgroud)

A有一个捕获this指针的lambda成员.运行上面的代码时,lambda在从独立A实例调用时工作正常,但是当从存储在向量中的实例调用时,我会遇到分段错误.

为什么会这样?

Pra*_*ian 8

您的示例有几个不同的问题.这条线

std::vector<A> as({});
Run Code Online (Sandbox Code Playgroud)

构造一个空的vector.当您索引到下一行的第一个元素时,您有未定义的行为,并且在这种情况下您的程序崩溃.

如果你改变它

std::vector<A> as;
as.emplace_back();
a[0].f();
Run Code Online (Sandbox Code Playgroud)

代码将按预期工作,但这并不意味着没有更多问题.如果你再添加一些元素vector,它将重新分配存储以容纳新元素,并且之前存储的lambda将被移动构造.但是当发生这种情况时,它们仍将保留其旧的this指针值,这些指针指向现在已经死亡的对象.之后调用lambda是未定义的行为.

这是潜在问题的一个例子

class A
{
public:
  A() :
    s("dummy"),
    f([&, this]{ std::cout << this << '\n'; return s == "dummy"; })
  {}
  std::string s;
  std::function<bool ()> f;
};

int main()
{
  std::vector<A> as;
  {
    A a;
    a.f();
    as.push_back(a);  // make a copy of a
    as[0].f();        // this pointer stays the same as the original
  } // lifetime of a ends

  as[0].f();  // undefined behavior
}
Run Code Online (Sandbox Code Playgroud)

现场演示

  • @Spagnol不,它不起作用.试着理解我在答案中所说的内容,你对lambda的问题比其他空括号可以解决的问题更严重.将`std :: vector <A>写为({{}});`表示添加到向量中的元素是从初始化列表中的元素复制构造的,并且存在上述所有的'this`指针问题.见[本例](http://coliru.stacked-crooked.com/a/ee7c35d04839d2a3); 请注意,lambda中打印的`this`指针与初始化列表中的元素匹配,并在该对象被销毁后打印. (2认同)