为什么lambda中通过引用捕获的值被破坏了?

时间:2015-09-14 18:54:06

标签: c++ c++11 lambda boost-asio

可重复的例子:

#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)
        {

        }
    }
}

输出:

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

为什么?按价值捕获正如我所期望的那样,但为什么通过引用捕获表现得像这样?

注意 int这里仅举例说明,考虑任何通过值传递不好的大对象(例如,消耗性副本)

为什么我宣布test1test2test1(const int& t_a)test2(const int& t_a)一切正常呢?

3 个答案:

答案 0 :(得分:4)

t_a的引用仅在void test2(int t_a)范围内有效。 在您的情况下按值捕获。

答案 1 :(得分:1)

不幸的是,C ++还没有提供垃圾收集器,因此闭包的使用有些受损。

您可以通过引用捕获(例如,具有引用相同捕获对象的多个闭包),但必须保证对象的生命周期独立于闭包的生命周期;换句话说,如果通过引用捕获变量的lambda在引用的对象中存活并且在对象已经被销毁时被调用,那么你将进入通常的&#34;未定义的行为&#34;领域

这是你的代码中发生的事情:捕获的变量是函数的一个参数,当调用闭包时它已经被破坏了。

解决方案是按值捕获(在这种情况下,捕获对象是在闭包内复制而你没有生命周期问题)或使用例如像std::shared_ptr这样的引用计数智能指针到一个免费商店分配的对象,以确保只要关闭存活引用(指向)对象也存活。

答案 2 :(得分:1)

因为引用是悬空。它引用一个函数参数,一旦函数返回就会停止存在。该函数在异步代码运行之前返回。

当然可以按价值捕捉t_a吗?