coroutine_handle 是指向协程帧的轻量指针,非协程本身;仅支持 resume/suspend/destroy 已存在帧,须从可信路径获取,空或已 destroy 的 handle 调用操作将导致未定义行为。

coroutine_handle 是什么:它不是协程本身,而是一个轻量指针
coroutine_handle 就像一个遥控器——它不包含协程栈、局部变量或执行上下文,只存着指向协程帧(coroutine frame)的裸指针。你不能靠它“创建”协程,只能用它去resume、suspend、destroy已存在的协程帧。
常见错误现象:coroutine_handle::from_address(nullptr) 后直接 resume(),程序崩溃;或者把 handle 复制多次后,多次 destroy() 同一帧,触发 double-free。
- 必须从
co_await表达式、promise_type::get_return_object()或coroutine_handle::from_promise()等可信路径获取有效 handle - 空 handle(
handle.done() == true且未 resume 过)调用resume()是未定义行为 - 一旦
destroy()调用成功,该 handle 变成悬垂指针,不能再用于任何操作
resume / suspend / destroy 的调用时机和前提
这三个操作不是对称的:你只能在协程处于 suspended 状态时 resume(),也只能在 suspended 或 initial 状态时 destroy();但 suspend() 是协程内部主动行为,外部无法强制调用。
使用场景:手动实现协程调度器、异步 I/O 回调唤醒、资源清理钩子。
立即学习“C++免费学习笔记(深入)”;
-
resume()前务必检查handle.done() == false,否则可能 resume 已结束的协程(UB) -
destroy()前建议先if (!handle.done()) handle.resume();确保协程走到 final_suspend,再 destroy —— 否则 promise 对象可能没被析构 - 不要在
promise_type::unhandled_exception()里直接handle.destroy(),此时协程帧可能还没完全建立
coroutine_handle 和 coroutine_handle 的区别在哪
的区别在哪
coroutine_handle 是最简形式,只能访问帧地址、done()、resume() 等基础操作;coroutine_handle(P 是 promise 类型)才能通过 handle.promise() 安全拿到 promise 引用,进而读写状态、传递结果。
参数差异直接影响你能做什么:
- 从
co_await返回的 handle 通常是coroutine_handle,除非你显式 cast -
coroutine_handle是合法的,但::from_promise(p) coroutine_handle编译失败 —— 类型不匹配::from_promise(p) - 跨线程传递 handle 时,用
void版本更安全(避免模板实例化爆炸),但后续必须用reinterpret_cast或静态断言还原类型才能访问 promise
容易被忽略的生命周期陷阱:promise 析构 vs 协程帧释放
协程帧内存(含 promise 对象)由分配器管理,destroy() 会触发帧释放,但 promise 的析构函数可能早在 final_suspend 之后就被调用了 —— 这取决于 promise_type 是否在 final_suspend() 返回 suspend_always。
性能影响:频繁手动 destroy() 并不会加速内存回收,反而可能干扰 allocator 的局部性;兼容性上,MSVC 和 Clang 对 coroutine_handle::address() 的返回值解释略有差异(是否带对齐偏移)。
- 如果你在
final_suspend()返回suspend_always{},那么 promise 析构发生在destroy()时;若返回suspend_never{},promise 析构早在协程自然结束时就完成了 - 不要在 promise 析构函数里访问
this->coro_handle(如果存了 handle),因为此时 handle 可能已被destroy()过 - 调试时可用
handle.address()打印帧地址,但别拿它做跨平台指针算术 —— 标准没保证帧布局










