Vincent Robert
Vincent Robert

Reputation: 36130

How tu use a C++11 lambda asynchronously when capturing by reference

Can somebody explain the behavior of the following code?

When I explicitely convert my lambda to an std::function, the lambda correctly captures my variable n.

When it is implicitly converted to an std::function (using a temporary), then the capture fails.

I am using g++-4.9 (Ubuntu 4.9-20140406-1ubuntu1) 4.9.0 20140405 (experimental) [trunk revision 209157]

#include <chrono>
#include <iostream>
#include <memory>
#include <thread>

std::shared_ptr<std::thread> call(const std::function<void()>& functor)
{
    // Execute our functor asynchronously
    return std::make_shared<std::thread>([&functor]
    {
        // Make sure all temporary are deallocated
        std::this_thread::sleep_for(std::chrono::seconds(1));
        // Execute our functor
        functor();
    });
}

int main()
{
    int n{};
    std::cout << "in main   " << &n << std::endl;
    // -> in main   0x7fffd4e1a96c

    auto lambda = [&n]
    {
        std::cout << "in lambda " << &n << std::endl;
    };

    // Here we do an explicit convertion to std::function
    std::cout << "explicit convertion" << std::endl;
    auto function = std::function<void()>{ lambda };
    auto pThreadFunction = call(function);
    pThreadFunction->join();
    // -> in lambda 0x7fffd4e1a96c

    // Here we use an implicit convertion to std::function
    std::cout << "implicit convertion" << std::endl;
    auto pThreadLambda = call(lambda);
    pThreadLambda->join();
    // -> in lambda 0

    return 0;
}

Upvotes: 2

Views: 1763

Answers (1)

ecatmur
ecatmur

Reputation: 157354

The lifetime of a temporary constructed for binding to a const reference function parameter is the full-expression containing that function call, so your thread function is referring to a dangling reference.

You should only capture variables into a thread function by reference if you can guarantee that the lifetime of the variable contains the lifetime of the thread, as you have done in the case where function is a local variable in main.

One alternative would be to call join within the full-expression that constructs the temporary:

call(lambda)->join();

Another more general solution would be to capture functor by value in your thread function.

Upvotes: 3

Related Questions