You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C++协程初始await的await-ready/await-suspend异常捕获位置

C++协程初始await的await-ready/await-suspend异常捕获与编译器行为分析

异常的正确捕获位置

对于初始await表达式的await-ready或await-suspend阶段抛出的异常,应该在启动协程的调用方(比如main函数)的catch块中捕获,而非协程体内部的异常处理逻辑。

标准条款与行为逻辑

根据C++标准定义的协程执行框架:

{
  promise-type promise promise-constructor-arguments ;
  try {
     co_await promise.initial_suspend() ;
     function-body
  } catch ( ... ) {
     if (!initial-await-resume-called)
        throw ;
     promise.unhandled_exception() ;
  }
final-suspend :
  co_await promise.final_suspend() ;
}

其中initial-await-resume-called初始为false,仅在await-resume表达式求值前才会被设为true。当异常发生在await-ready或await-suspend阶段时,这个标志仍为false,协程体的catch块会直接将异常重新抛出,最终传播到启动协程的调用上下文。

同时标准明确规定:若await-suspend求值因异常退出,异常会被捕获、协程恢复后立即重抛——这里的"恢复"就是回到调用方的执行上下文,因此异常会被调用方的catch块捕获。

编译器行为正确性

Clang的行为符合C++标准的要求,而GCC 12.2.1出现的双free错误属于编译器实现bug,大概率是在处理异常时错误地重复释放了协程帧资源。该问题在后续GCC版本(如13及以上)中已被修复,建议升级编译器版本验证。

正确捕获的代码示例

以下是完整的可测试代码,展示如何在调用方捕获初始await阶段的异常:

#include <coroutine>
#include <iostream>

// 会在await_suspend抛出异常的awaiter
struct Thrower {
    bool await_ready() const { return false; }
    void await_suspend(std::coroutine_handle<>) const { throw 2; }
    void await_resume() const {}
};

// 协程promise类型
struct Promise {
    Thrower initial_suspend() { return {}; }
    auto final_suspend() noexcept { return std::suspend_never{}; }
    void unhandled_exception() { std::terminate(); }
    void return_void() {}

    struct promise_type : Promise {
        auto get_return_object() {
            return std::coroutine_handle<promise_type>::from_promise(*this);
        }
    };
};

using CoroHandle = std::coroutine_handle<Promise::promise_type>;

// 协程函数
CoroHandle test_coro() {
    co_return;
}

int main() {
    try {
        auto coro = test_coro();
        coro.resume(); // 触发初始await的await_suspend,抛出异常
        coro.destroy();
    } catch (int e) {
        std::cout << "捕获到异常:" << e << std::endl;
    }
    return 0;
}

运行这段代码(用Clang或新版GCC),main函数的catch块会成功捕获到await_suspend中抛出的异常。

内容的提问来源于stack exchange,提问作者Enlico

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.26 19:15:01