协程中throw异常必须由promise::unhandled_exception()捕获,否则触发std::terminate;异常需在awaiter::await_resume()中rethrow才能透出到调用方;内部try/catch仅作用于同次resume内,跨co_await需外层捕获。

协程函数里 throw 会怎样?
直接抛异常会崩溃,因为 co_await 挂起点不自动传播异常。协程的异常必须由 promise 对象接管,否则未捕获的异常触发 std::terminate。
常见错误现象:terminate called without an active exception 或程序静默退出,尤其在 co_await 后 throw 时极易发生。
- 所有协程函数(如返回
task<t></t>的函数)内部 throw,都必须确保其 promise_type 实现了unhandled_exception() - 标准库中
std::generator、std::task(C++23 TS)等已内置该逻辑;手写协程类型时必须自己补全 - 如果用
co_yield或co_return前 throw,且 promise 未处理,同样崩
如何让 co_await 调用方拿到异常?
靠 awaiter 的 await_resume() 重抛 —— 这是异常从协程体“透出”到调用栈的关键环节。
使用场景:你 co_await 一个自定义 awaitable(比如网络请求封装),它内部完成时可能失败,这时不能只设标志位,得真抛。
-
await_resume()函数体内必须检查是否存有异常(例如通过 promise 的成员std::exception_ptr),有则调用std::rethrow_exception() - 若
await_resume()不 rethrow,异常就卡在 promise 里,调用方永远 catch 不到 - 注意:
std::rethrow_exception()不会终止当前栈帧,但会按常规 C++ 异常路径向上冒泡
try/catch 在协程函数内部有用吗?
有用,但仅限于协程体(suspend point 之间)的局部捕获;跨 co_await 的异常无法被同一层 try/catch 捕获。
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
参数差异:协程函数的栈帧不是连续执行的,每次 co_await 返回后,控制权交还给调用方,原栈帧可能已被销毁。
- 在
co_await a;和co_await b;之间加 try/catch,只能捕获 a 完成后、b 开始前发生的异常(比如解析返回值时 throw) - 无法捕获
a自身 await_resume() 中 rethrow 的异常 —— 那个异常发生在调用方栈上 - 想统一处理整个协程链路的错误,应在最外层
co_await处 try/catch,或用co_await包装器做转换(如转成expected<t e></t>)
为什么 std::coroutine_handle::resume() 后 catch 不到异常?
因为 resume() 是底层 API,它不自动展开 promise 的异常传播机制;异常仍留在 promise 里,除非你手动调用 await_resume()。
性能 / 兼容性影响:绕过标准 awaiter 流程直接 resume,等于放弃协程协议的异常语义,和裸线程里 throw 一样危险。
- 不要对任意
coroutine_handle直接resume()后 expect catch —— 它不会进你的 try/catch 块 - 正确做法:始终通过 awaiter(即
co_await表达式)驱动协程,让编译器插入 await_suspend/await_resume 调用链 - 调试时可检查 promise 的
m_exception(命名依实现而定),但生产代码不该依赖这个细节
协程异常不是“多了一种 throw 方式”,而是整套控制流被切片后,异常传播路径也跟着分段了。漏掉任意一环的 rethrow 或 unhandled_exception 处理,异常就断在半路 —— 看似没报错,实则 silently dropped。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!










