c++ 协程异常处理 c++协程中如何正确抛出和捕获异常

酷雪小哥_3982

酷雪小哥_3982

2026-03-21

990人浏览

原创

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

c++ 协程异常处理 c++协程中如何正确抛出和捕获异常

协程函数里 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++ Code Review Master
C++ Code Review Master

组合式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++ 的入门与实战技巧!

相关文章

c++速学教程(入门到精通)
c++速学教程(入门到精通)

c++怎么学习?c++怎么入门?c++在哪学?c++怎么学才快?不用担心,这里为大家提供了c++速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

相关标签:

c++

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

相关专题

更多
堆和栈的区别
堆和栈的区别

堆和栈的区别:1、内存分配方式不同;2、大小不同;3、数据访问方式不同;4、数据的生命周期。本专题为大家提供堆和栈的区别的相关的文章、下载、课程内容,供大家免费下载体验。

2023.07.18

5147

5

堆和栈区别
堆和栈区别

堆(Heap)和栈(Stack)是计算机中两种常见的内存分配机制。它们在内存管理的方式、分配方式以及使用场景上有很大的区别。本文将详细介绍堆和栈的特点、区别以及各自的使用场景。php中文网给大家带来了相关的教程以及文章欢迎大家前来学习阅读。

2023.08.10

2288

6

线程和进程的区别
线程和进程的区别

线程和进程的区别:线程是进程的一部分,用于实现并发和并行操作,而线程共享进程的资源,通信更方便快捷,切换开销较小。本专题为大家提供线程和进程区别相关的各种文章、以及下载和课程。

2023.08.10

3818

6

go语言 数组和切片
go语言 数组和切片

本专题整合了go语言数组和切片的区别与含义,阅读专题下面的文章了解更多详细内容。

2025.09.03

1572

14

promise的用法
promise的用法

“promise” 是一种用于处理异步操作的编程概念,它可以用来表示一个异步操作的最终结果。Promise 对象有三种状态:pending(进行中)、fulfilled(已成功)和 rejected(已失败)。Promise的用法主要包括构造函数、实例方法(then、catch、finally)和状态转换。

2023.10.12

4200

6

html文本框类型介绍
html文本框类型介绍

html文本框类型有单行文本框、密码文本框、数字文本框、日期文本框、时间文本框、文件上传文本框、多行文本框等等。详细介绍:1、单行文本框是最常见的文本框类型,用于接受单行文本输入,用户可以在文本框中输入任意文本,例如用户名、密码、电子邮件地址等;2、密码文本框用于接受密码输入,用户在输入密码时,文本框中的内容会被隐藏,以保护用户的隐私;3、数字文本框等等。

2023.10.12

3543

6

LLVM自定义Pass怎么写
LLVM自定义Pass怎么写

本专题聚焦LLVM自定义Pass开发,整理Pass类结构、run()方法、PreservedAnalyses、CMake构建、插件注册、-load-pass-plugin加载和测试用例编写流程。

2026.09.30

80

10

LLVM RISC-V参数配置教程
LLVM RISC-V参数配置教程

本专题介绍LLVM对RISC-V基础ISA和扩展的支持方式,涵盖RV32、RV64、标准扩展、实验性扩展、厂商扩展、-menable-experimental-extensions和版本差异。

2026.09.30

80

14

LLVM IR中间表示入门指南
LLVM IR中间表示入门指南

本专题整理LLVM IR的核心概念,包括中间表示作用、模块结构、函数、基本块、SSA形式、类型系统和常见语法,帮助新手理解LLVM编译流程中的关键层。

2026.09.30

80

12

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Conan 2 Essentials 免费课程
Conan 2 Essentials 免费课程

共0课时 | 0人学习

CMake 与 Conan 集成实践
CMake 与 Conan 集成实践

共0课时 | 0人学习

Conan 2 高级依赖模型介绍
Conan 2 高级依赖模型介绍

共0课时 | 0人学习