co_await是编译器识别协程的语法标记,非可重载函数;需使表达式expr成为awaitable对象,通常通过在自定义类型中实现await_ready()、await_suspend()、await_resume()三个成员函数。

co_await 不是函数,是编译器触发点
你不能“定义”co_await本身——它不是可重载的函数名,而是 C++20 编译器识别协程的语法标记。真正需要你实现的是:让某个表达式 expr 能被 co_await expr 合法使用,即让 expr 成为一个 awaitable 对象。
怎么让一个类型支持 co_await?看三个成员函数
编译器遇到 co_await expr 时,会按顺序查找:
expr.operator co_await()operator co_await(expr)- 若
expr是类类型,查它是否有await_ready()、await_suspend(std::coroutine_handle)、await_resume()
最常用也最可控的方式是第三种:在自定义类型中实现这三个函数。例如:
struct sleep_awaitable {
std::chrono::milliseconds dur;
bool await_ready() const noexcept {
return dur h) noexcept {
// 投递到定时器线程或注册 epoll/kqueue
start_timer(dur, [h] { h.resume(); });
}
void await_resume() const noexcept {}
};
注意:await_suspend 返回 void 或 true 表示“挂起后立即返回调用方”,此时你必须确保 h 被安全持有(比如用 std::shared_ptr 包裹);返回 false 表示“我自行负责唤醒”,但必须在某个时刻调用 h.resume(),否则协程永久卡住。
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
常见错误:co_await 没反应、程序卡死
这不是 co_await 本身的问题,而是 awaitable 实现没对齐预期行为:
-
await_ready()总返回true→ 协程不挂起,直接往下跑,await_suspend根本不调用 -
await_suspend里忘了保存h或调用resume()→ 协程挂起后无人唤醒,主线程/调用方永远等不到返回 - 在
await_suspend的 lambda 中捕获协程局部变量(如[this])→ 协程帧可能已被移动或销毁,访问野指针 - 把
std::suspend_always{}直接co_await但没手动resume()→ 它只挂起,不唤醒,纯靠外部驱动
标准提供的 awaitable 类型有哪些?
标准库只提供了两个“占位符”类型,不带调度逻辑:
-
std::suspend_always{}:await_ready()恒为false,await_suspend立即返回void,必须靠外部调用handle.resume() -
std::suspend_never{}:await_ready()恒为true,不挂起,同步执行
std::future 在 C++23 才原生支持 co_await;C++20 中若想 co_await 一个异步操作,必须自己封装 awaitable,或依赖第三方(如 libunifex、cppcoro)。
最易忽略的一点:awaitable 对象的生命周期必须覆盖整个挂起期。如果它是个栈上临时对象,await_suspend 返回后就析构了,而唤醒回调还在试图访问它——未定义行为就来了。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!










