C++20 Coroutines
Purpose
Guide agents through C++20 coroutine mechanics: co_await, co_yield, co_return, implementing the required promise_type, understanding coroutine frame memory layout, debugging suspended coroutines in GDB, and reducing frame allocation overhead.
Triggers
- "How do co_await, co_yield, and co_return work?"
- "How do I implement promise_type for a coroutine?"
- "How does a coroutine suspend and resume?"
- "How do I debug a suspended coroutine in GDB?"
- "How much memory does a coroutine frame use?"
- "How do I write a generator with co_yield?"
Workflow
1. The three coroutine keywords
A function is a coroutine if it contains any of these three keywords. Its return type must be a coroutine type with a promise_type.
2. Minimal coroutine type — Task
3. Generator with co_yield
4. Awaitable — custom co_await target
5. Coroutine frame layout and memory
The compiler allocates a coroutine frame (heap object) containing:
- Local variables that live across suspension points
- The promise object
- The current suspension state (where to resume)
- A pointer to the resumption/destruction functions
6. Debugging suspended coroutines in GDB
7. Boost.Asio co_spawn and co_await
co_spawn launches coroutines on an executor; co_await chains completion tokens without callback nesting.
8. std::generator (C++23)
Lazy sequences without manual coroutine handle management — compiler provides std::generator promise type.
9. Coroutine frame layout in GDB
Suspended coroutines may not appear on stack until resumed — trace via stored coroutine_handle.
10. Compilation time impact
Coroutines increase template instantiation and header parsing cost:
Measure with g++ -ftime-report or clang -ftime-trace. Coroutine-heavy headers (Asio) benefit from unity builds sparingly — balance with RAM use.
11. Common pitfalls
Related skills
- Use
skills/compilers/cpp-templatesfor other advanced C++20 features - Use
skills/rust/rust-async-internalsfor Rust's equivalent Future/Poll model - Use
skills/debuggers/gdbfor GDB session management


