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

标签 c++ c++11 lambda

考虑以下最少的代码:

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

A 类有一个捕获 this 指针的 lambda 成员。运行上面的代码时,lambda 在从独立的 A 实例调用时工作正常,但在从存储在 vector 中的实例调用时出现段错误。

为什么会这样?

最佳答案

您的示例存在几个不同的问题。这条线

std::vector<A> as({});

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

如果你把它改成

std::vector<A> as;
as.emplace_back();
a[0].f();

代码将按您预期的那样工作,但这并不意味着不再有问题。如果您向 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
}

Live demo

关于存储在容器中的 C++ Lambda 捕获 "this",我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35121579/

相关文章:

c++ - 英特尔 MIC 卸载——它如何与 STL 配合使用?

c++ - 带模板类的任意个参数赋值

c++ - 如何将图像加载到 painter.drawimage 函数

python - python 中的嵌套范围

java - 当变量是由于调用提供 lambda 的方法而被赋值时,如何在 lambda 中使用变量?

c++ - 让 DrawText 打断一个字符串

c++ - 为什么 auto_ptr 专门用于 void?

c++ - nothrow 在 C++11 中构造虚类

c++ - 当使用由 std::unique_ptr 定义的一元运算时,术语在 std 算法中不计算为 1 个参数

c++ - 具有模板参数的通用 lambda 函数