Skip to main content
A suspend point in C++ is a specific location within a C++20 coroutine where execution is temporarily halted, yielding control back to the caller or resumer. At this point, the compiler ensures that the coroutine’s execution state—including local variables, temporaries, and the instruction pointer—is preserved in a coroutine frame (typically dynamically allocated, though subject to Coroutine Heap Allocation Elision Optimization, or HALO). This state preservation allows execution to be resumed from the exact same location at a later time. Suspend points are explicitly or implicitly triggered by three keywords:
  • co_await expr: Evaluates an awaitable expression, potentially suspending the coroutine while waiting for a computation.
  • co_yield expr: Suspends execution and yields a value to the caller. This is syntactic sugar for co_await promise.yield_value(expr).
  • co_return expr: Evaluates the return expression, invokes promise.return_value(expr) (or promise.return_void()), destroys local variables in reverse order of creation, and subsequently transitions execution to the implicit final suspend point.

The Mechanics of Suspension

When the compiler encounters a suspend point via co_await, it evaluates an Awaitable expression. The compiler converts this Awaitable into an Awaiter object (e.g., via operator co_await() or the promise type’s await_transform()). The Awaiter must implement three specific methods that dictate the exact behavior of the suspension:
  1. await_ready(): Returns a bool. If true, the coroutine does not suspend, avoiding the overhead of context switching.
  2. await_suspend(std::coroutine_handle<PromiseType>): Called immediately after the coroutine is considered suspended and its state is saved, but before control is returned to the caller. It receives a strongly-typed handle to the suspended coroutine (though the awaiter may choose to accept a type-erased std::coroutine_handle<void> via implicit conversion). Because the coroutine is already suspended at this stage, another thread can resume (and potentially destroy) the coroutine while await_suspend is still executing.
  3. await_resume(): Called to obtain the result of the co_await expression. If the coroutine suspended, this is called immediately after resumption. If await_ready() returned true, it is called immediately without any suspension occurring.

Compiler Transformation

To visualize the mechanics of a suspend point, consider the following conceptual transformation performed by the C++ compiler when it encounters a co_await expression:

Implicit Suspend Points

In addition to explicit keywords within the coroutine body, the C++ coroutine specification mandates two implicit suspend points managed by the coroutine’s Promise type:
  1. Initial Suspend Point: Occurs immediately after the coroutine frame is allocated, arguments are copied, and the promise object is constructed, but before the user-authored coroutine body begins executing. It is executed as co_await promise.initial_suspend().
  2. Final Suspend Point: Occurs after the coroutine body has finished executing (via co_return or falling off the end) and local variables have been destroyed. It is executed as co_await promise.final_suspend(). Suspending at the final suspend point keeps the coroutine frame alive so the caller can extract the final result or observe the completion state.
Tired of Poor C++ Skills? Fix That With Deep Grasping!Learn More