Ответ вслух Senior Современный C++20/23 обновлено

Корутины C++ изнутри

Вопрос

Объясните, как устроены корутины в C++20: что делает компилятор, что такое promise_type и awaitable, и где их применяют.

Попробуйте сами

Ответьте вслух за 2 минуты, как на собесе. Потом сверьтесь с тезисами: что прозвучало, а что нет.

Показать ответ и разбор

Коротко

Функция становится корутиной, если в ней есть coawait, coyield или coreturn. Компилятор переписывает её в машину состояний: локальные переменные и номер точки возобновления хранятся в кадре корутины, который по умолчанию выделяется в куче (оптимизатор может убрать аллокацию).

Что должно прозвучать в ответе

  • Функция с co_await/co_yield/co_return становится корутиной

  • Кадр корутины в куче (с возможной оптимизацией HALO), coroutine_handle

  • promise_type управляет созданием, initial/final_suspend, результатом и исключениями

  • Awaitable: await_ready, await_suspend, await_resume

  • Бесстековые: приостановка только в самой корутине

  • Применение: генераторы, асинхронный ввод-вывод, std::generator в C++23

Что могут спросить следом

  • Чем корутины отличаются от потоков?
  • Как избежать висячих ссылок в параметрах корутины?

Разбор

Функция становится корутиной, если в ней есть co_await, co_yield или co_return. Компилятор переписывает её в машину состояний: локальные переменные и номер точки возобновления хранятся в кадре корутины, который по умолчанию выделяется в куче (оптимизатор может убрать аллокацию). Управлять ею можно через std::coroutine_handle. Поведение определяет promise_type из возвращаемого типа: он создаёт объект-результат, решает, приостановиться ли в начале и в конце (initial_suspend, final_suspend), принимает значения из co_yield и co_return и необработанные исключения. co_await expr работает с awaitable-объектом: await_ready говорит, можно ли не засыпать, await_suspend получает handle и решает, кто и когда нас возобновит, например планировщик ввода-вывода, await_resume возвращает результат. Корутины бесстековые, поэтому они лёгкие, но приостановиться можно только в самой корутине. Сами по себе они не дают параллелизма. Применяют для генераторов, в C++23 есть std::generator, и для асинхронного кода без колбэков. Главная ловушка: параметры по ссылке и захваты лямбд должны пережить корутину, которая может продолжиться позже.

Ответьте сами, а не прочитайте

В тренажёре вопрос попадёт в повторения и вернётся, когда начнёт забываться. Плюс билеты с зачётом: 20 вопросов, не больше 2 ошибок.