传递已超出作用域的lambda给std::thread是否安全?
问题场景
考虑以下代码:
#include <iostream> #include <thread> #include <chrono> int main() { std::thread t; { auto my_lambda = []{ int idx = 0; while (true) { std::this_thread::sleep_for (std::chrono::seconds(1)); std::cout << idx ++ << std::endl; } }; t = std::thread(my_lambda); } t.join(); return 0; }
问题:线程运行已超出作用域的lambda函数是否安全?
已知std::thread构造函数接收万能引用参数Function&& f,lambda会被转换为结构体。若该结构体实例在作用域内创建,线程是否会调用悬垂引用的operator()?
{ struct lambda_translated { void operator()(){ ... } }; lambda_translated instance; t = std::thread(instance); }
但不确定上述推理是否正确。
附加疑问
若在std::thread构造函数内将lambda声明为右值,行为是否会改变?
#include <iostream> #include <thread> #include <chrono> int main() { std::thread t; { t = std::thread([]{ int idx = 0; while (true) { std::this_thread::sleep_for (std::chrono::seconds(1)); std::cout << idx ++ << std::endl; } }); } t.join(); return 0; }
解答
不管是传递lambda左值还是右值的情况,线程运行都是安全的,核心原因如下:
std::thread构造函数在接收可调用对象时,会复制或移动一份对象副本到线程内部的独立存储区域,该区域的生命周期和线程绑定,不受原作用域影响,会持续到线程执行完毕。- 第一个例子中,
std::thread会复制作用域内的my_lambda实例到线程内部;第二个例子里的临时lambda(右值),则会被移动(或复制)到线程存储区。 - 线程实际执行的是内部副本的
operator(),原作用域内的lambda实例销毁不会对线程造成任何影响——线程从始至终都没有引用原实例,完全依赖自身持有的副本。
你之前的推理误区在于误以为线程会调用原实例的悬垂引用,但std::thread的设计就是为了避免这种风险,它会确保可调用对象的生命周期与线程绑定,而非依赖原作用域的对象。
内容的提问来源于stack exchange,提问作者Luckk
相关产品推荐
相关产品推荐

