考虑以下最少的代码:
#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
}
关于存储在容器中的 C++ Lambda 捕获 "this",我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35121579/