Короткий ответ: нет — это не автоматически безопасно. Возвращать ссылку на локальную переменную в coroutine может быть корректно только при строгом соблюдении условий жизни coroutine‑фрейма; в общем случае такое поведение даст висячую ссылку (UB).
Развернуто:
- В обычной (не‑корутинной) функции ссылка на локальную переменную — однозначно UB: переменная уничтожается при выходе из функции.
- В coroutine локальные переменные (и всё содержимое стека, нужное для продолжения) компилятор помещает в coroutine frame, которое живёт дольше, чем выполнение тела функции: frame существует пока существует handle/объект корутины и пока корутина не была завершена/уничтожена. Это значит, что ссылка на локальную переменную корутины может быть валидной некоторое время после "возвращения" корутины — в отличие от обычной функции.
- Однако это НЕ делает возвращение const_reference "по‑умолчанию безопасным":
- Если вызывающий код получит ссылку, а затем coroutine завершится и frame будет уничтожен — ссылка станет висячей.
- Поведение зависит от того, как устроен тип возвращаемого значения (promise_type) и жизненный цикл корутины (кто хранит handle, когда frame удаляется и т.д.).
- Например, в генераторе, который хранит frame пока жив объект генератора, co_yield ссылки на переменные внутри frame может быть безопасным в пределах существования генератора. Но если вы co_return и потом frame удаляется — ссылка уже невалидна.
Примеры
- Небезопасно (в общем случае):
auto get_text() -> std::string const& {
std::string s = "hi";
co_await some_suspend; // превращает функцию в корутину => s хранится в frame
return s; // возвращаем ссылку на объект в frame
}
Если caller не сохраняет coroutine‑handle и frame уничтожается — ссылка дёрганая.
- Безопасно только если вы гарантируете, что frame будет жить настолько долго, насколько нужен объект:
generator<std::string&> gen() {
std::string s = "...";
co_yield s; // потребитель может использовать ссылку, пока объект generator жив
}
Здесь ссылка валидна до тех пор, пока жив объект generator и frame не уничтожен.
Рекомендации
- Предпочитайте возвращать по значению (и полагайтесь на move/NRVO) — самый простой и безопасный путь.
- Если нужно избежать копий, явно храните объект в месте с контролируемым временем жизни (в promise, в heap через shared_ptr/unique_ptr, в объекте-генераторе) и возвращайте ссылку только при гарантированном lifetime.
- Не полагайтесь на «магическое» продление жизни локальных переменных корутины без явного управления жизненным циклом frame.
Итого: теоретически возможно вернуть ссылку на локальную переменную корутины и иметь корректное поведение, но это хрупко и требует явного управления временем жизни coroutine‑frame — поэтому считать такой код безопасным по умолчанию нельзя.