为什么在lambda中被引用捕获的值是坏的
Why value captured by reference in lambda is broken?
可重复示例:
#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
,肯定吗?
相关文章:
- C++Boost Asio Pool线程,带有lambda函数和传递引用变量
- c++ lambda:柯里和函数:使用按值捕获与按引用捕获返回不同的结果
- 引用捕获和在 lambda 中通过引用发送参数有什么区别 (C++)
- 修改在 std::future 的 lambda 中引用捕获的值
- clang++ 9.0 如何神奇地治愈 lambda 中的悬空引用使用?
- 为什么 lambda nullptr 取消引用在这种情况下有效?
- 仅通过引用捕获的 lambda 表达式是否保证不会抛出?
- 当lambda执行时,C++lambda捕获的引用具有不同的值
- 无法通过引用捕获 lambda 中的成员变量
- 在 lambda 中从引用类型捕获的值的类型,不使用通用捕获
- 将引用和指针传递给 lambda
- 为什么访问我的引用捕获变量会导致我的 lambda 函数出现段错误?
- 我无法通过引用捕获传递 lambda
- 我们应该在 lambda 中通过常量引用来捕获吗?
- 在 lambda 中通过引用捕获thread_local变量无法按预期工作
- lambda 表达式中引用捕获的 constexpr 变量和非显式捕获的 constexpr 变量之间的区别
- 列出生成器(lambda的向量)会导致通过引用捕获的非常奇怪的行为
- 无法使用带有常量引用的 lambda 对 std::vector 进行排序
- 为什么在重载的 ostream 运算符中引用 lambda 中的向量会导致错误
- 通过复制和decltype引用Lambda捕获