调用resume后,std::coroutine_handle::done为何始终返回false?
C++协程coroutine_handle::done()返回false的原因及解决方法
我编写了一个用于理解基础的简单C++协程示例,但无法理解为何coroutine_handle对象的done()方法仍返回false。我已调用resume,且后续没有更多co_await语句。以下是我的代码:
#include <coroutine> #include <iostream> struct ReturnObject { struct promise_type { ReturnObject get_return_object() { return {std::coroutine_handle<promise_type>::from_promise(*this)}; } std::suspend_never initial_suspend() noexcept { return {}; } std::suspend_never final_suspend() noexcept { return {}; } void unhandled_exception() {} void return_void() noexcept {} }; ReturnObject(std::coroutine_handle<> h) : h_{h}{ } std::coroutine_handle<> h_; }; ReturnObject foo() { std::cout << "1. Hello World!\n"; co_await std::suspend_always{}; std::cout << "2. Hello World!\n"; } int main(int argc, char** argv) { ReturnObject ret_object = foo(); ret_object.h_(); std::cout << ret_object.h_.done() << std::endl; return 0; }
调用resume后已无更多co_await,但done()方法始终返回false,请问我忽略了什么?
问题根源
问题出在promise_type中的final_suspend()函数:
- 当协程执行完所有代码(即
foo()中的2. Hello World!输出后),会调用return_void(),随后进入final_suspend()阶段。 - 你当前返回的是
std::suspend_never,这意味着协程会立即销毁自身,而不是挂起。此时coroutine_handle变成了悬空句柄,调用done()属于未定义行为,你看到的false是这种未定义行为的表现。 coroutine_handle::done()返回true的前提是:协程处于挂起状态(包括挂起在final_suspend点)。如果协程已经被销毁,句柄不再有效,done()的返回值没有意义。
解决方法
修改promise_type的final_suspend(),让它返回std::suspend_always,这样协程执行完毕后会挂起在final_suspend点,此时done()会正确返回true。同时,你需要手动调用coroutine_handle::destroy()来销毁协程,避免内存泄漏:
修改后的代码:
#include <coroutine> #include <iostream> struct ReturnObject { struct promise_type { ReturnObject get_return_object() { return {std::coroutine_handle<promise_type>::from_promise(*this)}; } std::suspend_never initial_suspend() noexcept { return {}; } // 将final_suspend改为返回suspend_always std::suspend_always final_suspend() noexcept { return {}; } void unhandled_exception() {} void return_void() noexcept {} }; ReturnObject(std::coroutine_handle<> h) : h_{h}{ } std::coroutine_handle<> h_; }; ReturnObject foo() { std::cout << "1. Hello World!\n"; co_await std::suspend_always{}; std::cout << "2. Hello World!\n"; } int main(int argc, char** argv) { ReturnObject ret_object = foo(); ret_object.h_(); std::cout << std::boolalpha << ret_object.h_.done() << std::endl; // 现在会输出true ret_object.h_.destroy(); // 手动销毁协程,避免内存泄漏 return 0; }
补充说明
std::boolalpha用于让输出显示true/false而不是1/0,方便查看结果。- 如果你坚持使用
std::suspend_never作为final_suspend的返回值,那么协程会在执行完后立刻销毁,此时绝对不能再使用对应的coroutine_handle(包括调用done()),否则会触发未定义行为。
内容的提问来源于stack exchange,提问作者Cabbas
相关产品推荐
相关产品推荐

