Search code examples
c++lambdaclosurescopy-constructorstd-function

lambda capture of std function


The following code causes segmentation fault, but I can't understand why:

#include <iostream>
#include <vector>
#include <functional>
class State {public:int x; int y; State(int _x,int _y):x(_x),y(_y){}};
typedef std::function<bool (const State &s)> FuncT;
std::vector<FuncT> funcs_outside;
class Manager
{
    private: std::vector<FuncT> funcs;
    public:  void insert(const FuncT &g){funcs.push_back(g);}
    // public:  void insert(const FuncT &g){funcs_outside.push_back(g);}
    public:  FuncT getAnd()
    {
        // this should capture everything, no?
        return [=](const State &s)
        {
            bool b=true;
            for (const auto f:funcs)
            // for (const auto f:funcs_outside)
            {
                b = b && f(s);
            }
            return b;
        };
    }
};
FuncT foo(void)
{
    Manager m;
    m.insert([=](const State &s){return s.x<=s.y;});
    m.insert([=](const State &s){return s.x>=s.y;});
    return m.getAnd();
}
int main(int argc, char **argv)
{
    auto h = foo();
    std::cout << "h(3,3) = " << h(State(3,3)) << "\n";
    std::cout << "h(3,4) = " << h(State(3,4)) << "\n";
    std::cout << "h(7,2) = " << h(State(7,2)) << "\n";
    return 0;
}
  • The [=] should capture anything the lambda needs right?
  • When I replace funcs with funcs_outside, everything works well.
  • What am I doing wrong?

Solution

  • What am I doing wrong?

    getAnd returns a function object from a member function, which captures and accesses members.

    You call that member function on a local variable, and return the resulting function object to the outside of the scope. The members pointed by the function object no longer exist and calling the function object results in undefined behaviour.

    When I replace funcs with funcs_outside, everything works well.

    funcs_outside is a global object and you access it within its lifetime, so there is no problem.

    how can I fix this?

    You could for example capture a copy of the member instead:

    return [funcs = this->funcs](const State &s)