Согласно стандарту сопрограмма должна быть уничтожена только тогда, когда она приостановлена [dcl.fct.def.coroutine]
Если для вызова вызывается сопрограмма, не приостановлено, программа имеет неопределенное поведение.
Во время вычисления выражения ожидания внутри сопрограммы A предположим, что эта последовательность событий соответствует [expr.await] /5.1:
- сопрограмма A приостановлена, поскольку готово к ожиданию неверно;
- до передачи контроля вызывающей функции сопрограммы A, сопрограмма B является возобновлено;
- после того, как B также приостановлено, управляющие потоки возвращаются к вызывающей программе сопрограммы A.
Может ли сопрограмма A быть уничтожена после возобновления сопрограммы B, но до ее приостановки?
Пример кода:
#include <coroutine>
using namespace std;
struct task
{
struct promise_type;
using handle_type = coroutine_handle<promise_type>;
struct promise_type
{
handle_type resumer = nullptr;
auto
get_return_object(){
return task{handle_type::from_promise(*this)};
}
auto
initial_suspend(){
return suspend_always {};
}
auto
unhandled_exception(){}
auto
final_suspend(){
return suspend_always{};
}
void
return_void() {}
};
handle_type handle;
void await_resume(){
handle.resume();
}
auto
await_suspend(handle_type h){
handle.promise().resumer = h;
return handle;
}
auto
await_ready(){
return false;
}
};
int main(){
task coroutine_B = [&coroutine_B]() ->task
{
coroutine_B.handle.promise().resumer.destroy();
co_return;
}();//coroutine B supended at initial suspend
task coroutine_A = [&coroutine_B]() ->task
{
co_await coroutine_B;//set coroutine_B resumer to coroutine_A handle
//then resume coroutine_B.
}();//coroutine A supended at initial suspend.
coroutine_A.handle.resume();//execute co_await coroutine_B;
//is this UB?
}
Как видно здесь , код компилируется и, похоже, работает без проблем.
С другой стороны, это, по-видимому, эквивалентно версия здесь вылетает.