可重复示例:
#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
在这里只是一个例子,考虑任何大的对象不能按值传递(例如,消耗性副本)
为什么如果我声明test1
和test2
为test1(const int& t_a)
和test2(const int& t_a)
都是正常工作的?
对t_a
的引用只在void test2(int t_a)
范围内有效。按值捕获
遗憾的是c++还没有提供垃圾收集器,因此闭包的使用在某种程度上受到了损害。
你可以通过引用捕获(例如有多个闭包引用同一个捕获的对象),但是对象的生命周期必须独立于闭包的生命周期;换句话说,如果通过引用捕获变量的lambda在被引用的对象中幸存下来,并且在对象已经被销毁时被调用,那么您就进入了通常的"未定义行为"领域。
这是在你的代码中发生的事情:捕获的变量是函数的一个参数,当闭包被调用时,它已经被销毁了。
一个解决方案是按值捕获(在这种情况下,捕获对象被复制到闭包内部,你没有生命周期问题)或使用引用计数智能指针(如std::shared_ptr
)到自由存储分配的对象,以确保只要闭包存在,引用(指向)对象也存在。
因为引用悬空。它引用一个函数参数,一旦函数返回,该参数将不复存在。函数在异步代码运行之前返回。
按值捕获t_a
,肯定吗?