promise_type 的生命周期由编译器决定,随协程帧构造而创建、销毁而析构;需重载 final_suspend()、unhandled_exception() 和析构函数来干预销毁时机;保存 coroutine_handle 易导致悬空引用,应避免长期持有;自定义内存分配时 operator new/delete 必须成对且 delete 接受 size_t 参数,析构函数不可抛异常。

promise_type 的生命周期由谁决定?
它不归你管,归编译器管。协程帧(coroutine frame)分配时,promise_type 作为其成员被构造;协程结束(无论正常 return、co_return、异常退出或被 destroy)时,它被自动析构。你不能手动 new/delete 它,也不能靠外部引用延长它的生命——一旦协程帧释放,promise_type 就没了。
想控制“协程何时真正结束”,得重载哪些函数?
关键不是“延长 promise 对象寿命”,而是干预协程帧的销毁时机。核心是重写以下三个函数:
-
final_suspend():返回std::suspend_always或std::suspend_never,决定协程执行完后是否挂起(从而延迟销毁) -
unhandled_exception():异常未被捕获时调用,若想保活协程帧,这里别 throw,也别让协程直接销毁 -
~promise_type():析构函数里可以做清理,但此时协程帧已准备释放,不能再访问coroutine_handle所指向的栈变量
典型场景:实现一个可暂停等待的异步任务,用户调用 task.wait() 后才允许销毁,就靠 final_suspend() 返回 std::suspend_always,再暴露一个 resume() 方法手动恢复并触发销毁。
为什么在 promise_type 里存 coroutine_handle 容易出错?
因为 coroutine_handle 持有对协程帧的非拥有式引用。如果在 promise_type 构造函数里用 from_promise() 获取 handle 并保存为成员,可能触发未定义行为:
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
- 协程帧还没完全构造完,handle 可能指向未初始化内存
- 协程帧分配在栈上(如栈协程),而 promise 被你存到堆对象里,栈帧一退,handle 立即悬空
- 即使帧在堆上(
operator new分配),你也得确保 handle 不在 promise 析构后还被使用
安全做法:只在 get_return_object() 或挂起点(如 await_suspend())中临时获取 handle,不用长期持有。
自定义 promise_type 时最容易漏掉的析构约束
如果你重写了 operator new / operator delete 来控制协程帧分配,必须成对出现,且 operator delete 必须接受 size_t 参数(C++20 要求)。否则协程结束时可能调用默认 delete,导致内存泄漏或 double-free。
另外:promise_type 的析构函数不能抛异常。C++ 标准明确禁止,否则程序直接 terminate。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!










