协程函数需同时满足三个关键字(co_await/co_yield/co_return)和返回类型中定义promise_type,缺一不可;co_await不自动并发,仅挂起;awaitable需实现await_ready/await_suspend/await_resume三接口;co_yield仅用于generator且依赖yield_value。

协程函数写出来不等于能跑,缺 promise_type 就编译不过;co_await 不会自动并发,裸写它只会挂起、不会调度到其他线程。
怎么让一个函数变成协程?三个关键字和一个 promise_type 缺一不可
只要函数体里出现 co_await、co_yield 或 co_return 中任意一个,编译器就把它当协程处理。但光有关键字不够——返回类型必须嵌套定义 promise_type,否则报错类似 no type named 'promise_type' in 'MyTask'。
-
get_return_object():必须返回协程句柄对象(比如MyTask实例),里面通常存着coroutine_handle -
initial_suspend():决定协程创建后是否立刻挂起,常用std::suspend_always{}(创建即挂)或std::suspend_never{}(立即执行到首个co_await) -
final_suspend()和unhandled_exception()也必须实现,漏掉任何一个都会编译失败 - 如果函数声明为
MyTask<int></int>,就得提供return_value(int);若是MyTask<void></void>,就得有return_void()
co_await 等待什么?不是所有东西都能直接 await
co_await x 要求 x 是 “awaitable” —— 即满足三件套:await_ready()、await_suspend(coroutine_handle)、await_resume()。标准库里只有 std::suspend_always 和 std::suspend_never 是现成的 awaitable,但它们只是挂起/不挂起,不做任何调度。
- 想等一个 I/O 操作?不能直接
co_await socket.read(),得先封装成 awaiter,让它在await_suspend里把coroutine_handle交给 epoll 或 IOCP - 常见错误:给右值临时对象写
operator co_await()却没加const&重载,导致co_await make_awaiter()编译不过 -
await_suspend返回bool:true 表示已挂起,false 表示同步继续执行;返回void或另一个coroutine_handle是高级用法,慎用
co_yield 只属于 generator,别和 co_await 混用
co_yield x 的语义是“产出 x 并挂起”,底层调用的是 promise.yield_value(x)。它只该出现在 generator 类型(如 Generator<int></int>)中,且 promise_type 必须实现 yield_value 接口。
- 在
Task<int></int>里写co_yield 42?编译直接报错:no member named 'yield_value' -
co_yield不触发await_ready/await_suspend,和co_await完全无关,别指望它能做异步等待 - generator 的生命周期管理很关键:
coroutine_handle必须在 promise 对象还活着时调用resume(),否则未定义行为
最易被忽略的是:协程帧(frame)内存默认由 operator new 分配,但你没显式控制的话,异常抛出或提前销毁可能导致泄漏或 double-delete;promise_type 里的 operator new 和 operator delete 才是真正管这事的地方。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











