Why value captured by reference in lambda is broke

2019-07-14 05:00发布

This question already has an answer here:

Repeatable example:

#include <iostream>
#include <boost/asio/io_service.hpp>

boost::asio::io_service io_service;

void test1(int t_a)
{
    std::cout << "in test1: t_a = " << t_a << std::endl;
}

void test2(int t_a)
{
    std::cout << "in test2: t_a = " << t_a << std::endl;

    io_service.post([&t_a]()
    {
        std::cout << "in test2 post lambda: t_a = " << t_a << std::endl;
        test1(t_a);
    });
}

int main(int, char**)
{
    int a = 42;

    for (;;) {
        try
        {
            test2(a);
            io_service.run();
            break;
        }
        catch (std::exception & e)
        {

        }
    }
}

Output:

in test2: t_a = 42
in test2 post lambda: t_a = 16451253
in test1: t_a = 16451253
Press any key to continue . . .

Why is that? Capturing by value is working as I expect it to, but why does capturing by reference behave like this?

Note int here is only for example, consider any big object which is bad to pass by value (expendable copy, for example)

Why if I declare test1 and test2 as test1(const int& t_a) and test2(const int& t_a) all is working correctly then?

3条回答
2楼-- · 2019-07-14 05:37

The reference of t_a is valid only in void test2(int t_a) scope. Capture by value in your case.

查看更多
贼婆χ
3楼-- · 2019-07-14 05:42

Unfortunately C++ doesn't provide a garbage collector (yet) and therefore the use of closures is somewhat impaired.

You can capture by reference (thus for example having multiple closures referencing the same captured object) but the lifetime for the object must be guaranteed independently from the lifetime of the closures; in other words if a lambda capturing a variable by reference survives the referenced object and is called when the object has already been destroyed then you get in the usual "undefined behavior" realm.

This is what happens in your code: the captured variable is a parameter of the function and when the closure is called it has already been destroyed.

A solution is either capture by value (in this case the capture object is copied inside the closure and you don't have a lifetime problem) or use for example a reference-counted smart pointer like std::shared_ptr to a free-store allocated object to ensure that as long as the closure survives the referenced (pointed-to) object also survives.

查看更多
甜甜的少女心
4楼-- · 2019-07-14 05:42

Because the reference is dangling. It refers to a function argument, which will cease to exist as soon as the function returns. The function returns before your asynchronous code runs.

Just capture t_a by value, surely?

查看更多
登录 后发表回答