为什么在lambda中被引用捕获的值是坏的

Why value captured by reference in lambda is broken?

本文关键字:引用 lambda 为什么      更新时间:2023-10-16

可重复示例:

#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)都是正常工作的?

t_a的引用只在void test2(int t_a)范围内有效。按值捕获

遗憾的是c++还没有提供垃圾收集器,因此闭包的使用在某种程度上受到了损害。

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

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

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

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

按值捕获t_a,肯定吗?