Boost Asio C++20协程:co_spawn按引用传参出现异常结果
问题:协程参数按引用传递时输出异常的原因分析
现象复现
当session协程的参数使用const std::string&按引用传递时:
#include <boost/asio.hpp> #include <iostream> boost::asio::awaitable<void> session(const std::string& name) { std::cout << "Starting " << name << std::endl; auto executor = co_await boost::asio::this_coro::executor; } int main() { boost::asio::io_context io_context; co_spawn(io_context, session("ServerA"), boost::asio::detached); co_spawn(io_context, session("ServerB"), boost::asio::detached); io_context.run(); return 0; }
编译运行后出现异常输出:
> g++ -std=c++20 ../test-coro.cpp -o test-coro && ./test-coro Starting ServerB Starting ServerB
而将参数改为按值传递后:
#include <boost/asio.hpp> #include <iostream> boost::asio::awaitable<void> session(std::string name) { std::cout << "Starting " << name << std::endl; auto executor = co_await boost::asio::this_coro::executor; } int main() { boost::asio::io_context io_context; co_spawn(io_context, session("ServerA"), boost::asio::detached); co_spawn(io_context, session("ServerB"), boost::asio::detached); io_context.run(); return 0; }
运行结果正常:
> g++ -std=c++20 ../test-coro.cpp -o test-coro && ./test-coro Starting ServerA Starting ServerB
请问此现象是预期行为还是编译器/库的Bug?若为预期行为,原因是什么?
环境:Arch Linux 5.18.16-arch1-1,gcc (GCC) 12.2.0,boost版本1.79
回答
这是预期行为,本质是临时对象生命周期与协程调度时机不匹配导致的未定义行为,具体原因如下:
- 调用
session("ServerA")时,会创建一个临时的std::string对象,这个临时对象的生命周期仅局限于当前表达式语句,语句执行完毕后就会被销毁。 - Boost.Asio的
co_spawn函数并不会立刻执行协程体,它会将协程包装成任务加入到io_context的队列中,等待后续调度执行。 - 当协程真正被调度执行时,原先的临时
std::string已经被销毁,此时引用指向的是已释放的内存空间,这属于C++标准中的未定义行为。你看到两次输出"ServerB"只是未定义行为的一种表现形式——比如第一个临时对象的内存被第二个临时对象覆盖,导致两个协程都读取到了后续的值。 - 改为按值传递时,
std::string参数会被拷贝到协程的内部状态中,其生命周期与协程绑定,直到协程执行完毕才会销毁,因此能正确访问参数值。
内容的提问来源于stack exchange,提问作者R.J
相关产品推荐
相关产品推荐

