Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ Lambda stored in container capturing "this"

Tags:

c++

c++11

lambda

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?

like image 266
Spagnol Avatar asked Mar 04 '26 17:03

Spagnol


1 Answers

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

like image 113
Praetorian Avatar answered Mar 06 '26 08:03

Praetorian



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!