Lambda passed by reference runs when invoked in the constructor, but not when later stored in a data member

You’re not storing a lambda, you’re storing a reference to a std::function.

In fact, that std::function is being created as a temporary when the lambda is implicitly converted to std::function. That std::function temporary dies after the line where the constructor is invoked.

    LambdaStore(const std::function<void(float)>& _fn) // _fn refers to a temporary
    : fn(_fn)
    {
        fn(11.1f);    // works
    } // fn (and _fn) dies

But, even if you would change your class to use the lambda type directly through a template, the lambda itself would die too, but this is true with any C++ type, no matter the type. Consider with ints:

class LambdaStore
{
public:
    LambdaStore(const int& _i)
    : i(_i)
    {
        std::cout << i;    // works
    }

    void ExecuteStoredLambda()
    {
        std::cout << i;    // crashes
    }

private:
    const int& i;
};

void main()
{
    LambdaStore lambdaStore(1); // temporary int created here
    // temporary int gone

    lambdaStore.ExecuteStoredLambda();
}

Temporaries don’t get lifetime extension past the statement they are created for when they are bound to a function parameter.

They do get lifetime extension if it binds directly to a member reference, when using the braces only, though:

struct ref {
    const int& i
};

int main() {
  ref a{3};

  std::cout << a.i; // works

  ref b(3);

  std::cout << b.i; // crashes
}

The solution is obviously to store the std::function by value instead of by reference:

class LambdaStore
{
public:
    LambdaStore(const std::function<void(float)>& _fn)
    : fn(_fn)
    {
        fn(11.1f);    // works
    }

    void ExecuteStoredLambda()
    {
        fn(99.9f);    // will also work
    }

private:
    std::function<void(float)> fn; // no & here
};

Leave a Comment

Hata!: SQLSTATE[HY000] [1045] Access denied for user 'divattrend_liink'@'localhost' (using password: YES)