Search code examples
c++objectreferencememberstd-function

C++: Cannot capture "this" context 2 times in lambdas


Below is a minimal code to reproduce the problem:

std::vector<std::function<bool()>> injections;
struct Obj {
    void load() {
        injections.push_back([&] {
            std::cout << ++counter << std::endl;
            injections.push_back([&] {
                std::cout << ++counter << std::endl;
                return true;
            });
            // std::cout << ++counter << std::endl;
            return true;
        });
    }
    int counter = 0;
};
int main() {
    Obj obj;
    obj.load();
    while(true)
        for(auto i = 0; i < injections.size(); i++) {
            auto pop = injections[i]();
            if(pop)
                injections.erase(injections.begin() + i--);
        }
}

Running exactly this way everything works right, but uncommenting the commented line, it crashes. The problem is that after pushing the second lambda, this points to some garbage, and the ++counter throws. I expect the first lambda to capture by reference the members, which are not gonna go out of scope after ending load(), which is what exactly happens. For the second lambda I expect to capture by reference the references, making counter available, which is again what happens using the bad line commented. It looks like the construction of the lambda invalidates everything after it. What's the reason for this and some solutions?


Solution

  • When you insert something in injections, previous std::function<bool()> might be moved (and destructed).

    So code after injections.push_back should no longer use captures/members.

    It is mainly equivalent to usage of delete this; in a method.