Consider the following minimal code:
#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
}
Class A has a lambda member that captures this pointer. When running the code above, lambda works fine when invoked from standalone A instance, but I get segmentation fault when called from an instance stored in the vector.
Why does it happen?
There are a couple of different problems with your example. This line
std::vector<A> as({});
constructs an empty vector. When you index into the first element on the next line, you have undefined behavior, and your program crashes in this case.
If you change that to
std::vector<A> as;
as.emplace_back();
a[0].f();
the code will work as you expect, but that doesn't mean there are no more problems. If you add a few more elements to your vector, it'll reallocate storage to accommodate the new elements, and the previously stored lambdas will get move constructed. But when that happens, they will still retain their old this pointer values, which point to objects that are now dead. Invoking the lambda after that is undefined behavior.
Here's an example of the potential problems
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With