Корутины (C++20)
Функции, которые умеют приостанавливаться, запоминать своё место и продолжаться позже
co_await, co_yield, co_return — которые превращают обычную на вид функцию в такую приостанавливаемую машину состояний. Эта единственная возможность лежит в основе двух совсем разных инструментов: ленивых генераторов (выдают значения по одному по требованию) и асинхронного кода без колбэков (пишем последовательный код в стиле await, который не блокирует поток).
- точно сказать, что делает функцию корутиной и что делают три ключевых слова
co_; - объяснить кадр корутины,
promise_typeиcoroutine_handle; - читать самописный
Generator, который лениво выдаёт значения черезco_yield; - увидеть, как
co_awaitзаменяет цепочки колбэков прямолинейным асинхронным кодом; - назвать честные компромиссы: кадры в куче, скромная библиотечная поддержка в C++20 и ловушки времени жизни.
1. Что делает функцию корутиной
Корутину не объявляют особым ключевым словом в сигнатуре. Функция становится корутиной, если её тело использует хотя бы одно из трёх ключевых слов:
co_await expr— возможно приостановиться, пока expr не будет готово, затем продолжить (и, при желании, получить результат).co_yield value— выдать одно значение вызывающему коду и приостановиться; эквивалентco_await promise.yield_value(value).co_return value— завершить корутину, при желании передав итоговый результат.
Компилятор переписывает такую функцию в машину состояний. Поскольку управление может покидать тело и снова в него входить, локальные переменные не могут жить в обычном стеке вызовов (кадр стека исчезает в момент приостановки). Вместо этого они живут в кадре корутины: блоке памяти, обычно в куче, где хранятся параметры, локальные переменные и небольшой служебный объект — promise (обещание).
promise_type корутины не имеет отношения к std::promise/std::future. Это точка настройки, с которой общается компилятор; напрямую вы её почти не трогаете — её предоставляет библиотечный тип.