Я знаю, что если будет достигнут co_return (неявный или явный)
co_await promise.final_suspend() называется.
В final_suspend() определенно можно вызвать handle.destroy(), который, насколько я понимаю, уничтожает все объекты в кадре сопрограммы (CF), наконец вызывает ~promise_type(), а затем освобождает выделенный CF. См. ниже Льюис Бейкер рекомендует это.
Однако:
Если final_suspend() не вызывает handle.destroy() или возвращает std::suspend_never или , будет ли CF правильно уничтожен сразу после этого
co_await promise.final_suspend() завершается?
Что произойдет, если final_suspend() вернется std::suspend_always?
Освобождение CF каким-то образом связано с деструктором ~promise_type(), выведенным компилятором?
*Льюис Бейкер рекомендует это здесь:
Обратите внимание, что хотя разрешено не приостанавливать сопрограмму в точке Final_suspend, рекомендуется структурировать свои сопрограммы так, чтобы они приостанавливались в точке Final_suspend, где это возможно. Это связано с тем, что это вынуждает вас вызывать
.destroy()в сопрограмме снаружи сопрограммы (обычно из какого-либо деструктора объекта RAII), и это значительно упрощает компилятору определение того, когда область времени жизни кадра сопрограммы вложена внутрь. звонивший. Это, в свою очередь, повышает вероятность того, что компилятор сможет исключить выделение памяти для кадра сопрограммы.
Кроме того, чтение комментариев к этому блогу ниже[1] заставило меня задуматься, гарантирует ли использование std::suspend_never отсутствие утечек. 1





Да. См. [dcl.fct.def.coroutine]/11: «Состояние сопрограммы уничтожается, когда управление переходит с конца сопрограммы или функции-члена destroy ([coroutine.handle.resumption]) дескриптора сопрограммы ( [coroutine.handle]), который ссылается на сопрограмму, вызывается [...]".
Сопрограмма приостанавливается в конечной точке приостановки, и поток управления возвращается к функции, которая вызвала сопрограмму или недавно возобновила ее, точно так же, как если бы сопрограмма была приостановлена в любой другой точке. (Обратите внимание, что вы можете реализовать await_suspend, который фактически указывает, какую сопрограмму возобновлять, кроме текущего вызывающего/возобновляющего объекта, но это выходит за рамки этого вопроса. std::suspend_always всегда возобновляет текущий вызывающий/возобновляющий объект.)
Нет. Вызов деструктора объекта обещания — это просто один из шагов, который происходит в рамках разрушения кадра сопрограммы. Это связано с тем, что объект обещания является локальной переменной в отключенной сопрограмме ([dcl.fct.def.coroutine]/5).
Кроме того, прочитав комментарии к этому блогу ниже, я задался вопросом, гарантирует ли использование
std::suspend_neverотсутствие утечки.
Он предотвращает один конкретный тип утечки памяти, то есть тот, когда вы забываете явно уничтожить сопрограмму после ее приостановки в конечной точке приостановки.
@dwto В основном это правильно, но на самом деле есть два способа возобновить работу сопрограммы. Вы можете либо явно вызвать resume для дескриптора, либо вернуть дескриптор из await_suspend ([expr.await]/5.1.1).
Спасибо! Возврат дескриптора из await_suspend работает только в том случае, если компилятор видит возможность оптимизации вызова сказки. Я ошибаюсь? И в любом случае он возвращает дескриптор продолжения await_suspen, т.е. получает int await_reume, я прав?
@dwto Если вы вернете дескриптор из await_suspend, сопрограмма, на которую ссылается этот дескриптор, будет возобновлена. Это поведение, определенное стандартом. Я не могу понять ваш вопрос. По любым дополнительным вопросам, пожалуйста, задайте новый вопрос.
Спасибо! stackoverflow.com/questions/78470532/…
Спасибо, Брайан Би! Что касается вашего комментария к 2. Верно ли это сказать: как только сопрограмма CORO будет приостановлена, поток вернется к: Если существовал возобновлятель, то есть функция, которая запускала дескриптор CORO::resume(), поток вернется к коду после этого самое последнее резюме. В противном случае он вернется к функции, которая в первую очередь вызвала CORO: т.е. запустила CORO(args). Исключением из этого правила является случай, когда, как вы говорите, сопрограмма имеет доступ к дескриптору другой сопрограммы и запускает handle.resume().