作为boost::asio::co_spawn完成句柄的局部lambda生命周期是否合法?
疑问:局部lambda作为boost::asio::co_spawn完成句柄的生命周期是否足够?
相关代码片段
void setup(boost::asio::io_context &context) { const auto completion_handler = [](std::exception_ptr ptr) { if (ptr) { std::cout << "Rethrowing in completion handler" << std::endl; std::rethrow_exception(ptr); } else { std::cout << "Completed without error" << std::endl; } }; boost::asio::co_spawn(context, coroutine_with_rethrow_completion_handler(), completion_handler); }
疑问与推理
这段代码中定义的局部lambda(completion_handler)生命周期是否足够?
我清楚捕获局部变量会因作用域失效引发问题,但对lambda自身的生命周期存疑:boost::asio::co_spawn的完成句柄参数是转发引用(&&),且官方文档未明确说明完成令牌的生命周期要求,担心asio内部仅存储lambda的引用,等setup函数退出后lambda销毁,后续执行io_context::run时会触发未定义行为。
完整可运行示例(MRE)
#include <iostream> #include <boost/asio.hpp> boost::asio::awaitable<void> coroutine_with_rethrow_completion_handler() { std::cout << "Coroutine executes with rethrow completion handler\n"; throw std::runtime_error("Test throw from coroutine!"); co_return; } void setup(boost::asio::io_context &context) { const auto completion_handler = [](std::exception_ptr ptr) { if (ptr) { std::cout << "Rethrowing in completion handler" << std::endl; std::rethrow_exception(ptr); } else { std::cout << "Completed without error" << std::endl; } }; boost::asio::co_spawn(context, coroutine_with_rethrow_completion_handler(), completion_handler); } int main() { boost::asio::io_context context; setup(context); std::thread t([&context]() { try { while (true) { context.run(); return; } } catch (std::exception &e) { std::cerr << "Exception in context::run(): " << e.what() << "\n"; } }); t.join(); }
解答
这个局部lambda的生命周期是完全足够的,不会引发未定义行为。
Boost.Asio的co_spawn函数会复制或移动传入的完成令牌(包括lambda)到内部存储中,直到协程执行完成并调用完句柄后,才会销毁这个存储的实例。也就是说,当setup函数退出时,asio已经持有了该lambda的副本(或移动后的实例),后续io_context::run调用完成句柄时,操作的是这个内部存储的副本,而非原局部lambda。
对于这个例子中的无捕获lambda来说,复制操作完全安全;即使lambda有捕获,只要捕获的对象自身生命周期足够(或捕获的是值而非引用),同样不会出现问题。
内容的提问来源于stack exchange,提问作者Superlokkus
相关产品推荐
相关产品推荐

