【问题标题】:Why value captured by reference in lambda is broken? [duplicate]为什么在 lambda 中通过引用捕获的值被破坏? [复制]
【发布时间】:2015-09-14 18:54:06
【问题描述】:

可重复的例子:

#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这里只是举例,考虑任何不能传值的大对象(例如可消耗的副本)

如果我将test1test2 声明为test1(const int&amp; t_a)test2(const int&amp; t_a),那么为什么一切正常?

【问题讨论】:

  • 您在其生命周期之外使用捕获的值,您可以找到类似的示例here

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


【解决方案1】:

t_a 的引用仅在void test2(int t_a) 范围内有效。 在您的案例中按价值捕获。

【讨论】:

  • 或者test2也通过引用接受它的参数,然后OP需要确保传递给test2的任何东西的生命周期超过asio调用的生命周期。
  • test2(int t_a) 范围是什么意思?我认为test2()体内的函数调用io_service.post在函数test2的范围内。
  • io_service.post(..) 注册函数,而io_service.run() 调用它。
【解决方案2】:

不幸的是,C++ 还没有提供垃圾收集器,因此闭包的使用受到了一定的影响。

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

这就是您的代码中发生的情况:捕获的变量是函数的参数,当调用闭包时,它已经被销毁了。

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

【讨论】:

  • 再过一会:为什么如果我将test1test2 声明为test1(const int&amp; t_a)test2(const int&amp; t_a) 那么一切都正常工作?
  • @vladon:纯粹的机会,有效的。好吧,取决于您将这些引用绑定到什么。我们不知道所指对象的生命周期是多少。
  • 原因是在这种情况下,通过引用捕获的变量在main中并且仍然足够活跃。
【解决方案3】:

因为引用是悬空。它指的是一个函数参数,一旦函数返回,该参数将不复存在。该函数在您的异步代码运行之前返回。

只需按价值捕获t_a,确定吗?

【讨论】:

  • int 这里只是举例,实际代码是针对对象的...
  • @vladon:那么您应该在问题中包含该详细信息。
  • 谢谢,我收录了
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-08-28
  • 2011-09-25
  • 2014-09-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多