Я добавляю поддержку сопрограмм ts в классе сокетов asyn c на основе портов завершения windows io. Без сопрограмм ввод-вывод может быть выполнен следующим образом:
sock.async_write(io::buffer(somebuff), [](auto&& ... args){ /* in handler */ });
или
sock.async_write(std::vector<io::const_buffer>{ ... }, [](auto&& ... args){ /* in handler */ })
, где каждый из них возвращает void и уведомляет результат через обработчик и не требует кеширования параметры, потому что операция будет передана по возвращении из функции
Но с сопрограммами функция вернет ожидаемое, что после ожидания с operator co_await
отправит операцию, поэтому мне нужно кэшировать параметры в можно избежать использования разрушенных временных файлов:
awaitable coro_write(const io::const_buffer& buff)
{
return awaitable{ *this, buff };
}
awaitable coro_write(const std::vector<io::const_buffer>& buffs)
{
return awaitable{ *this, buffs };
}
копия в первом случае не наносит вреда, а во втором - причиняет вред, поскольку она вызывает распределение кучи и копирует векторное содержимое.
Так что я искал решение этой проблемы, и, читая эту страницу сопрограммы ts я наткнулся на это:
Типичный генератор yield_value будет хранить (копировать / перемещать или просто сохранить адрес, так как время жизни аргумента пересекает точку приостановки внутри co_await) его аргумент int o объект генератора и возвращение std :: suspend_always, передавая управление вызывающей стороне / возобновителю.
и на той же странице указано, что выражение co_yield
эквивалентно:
co_await promise.yield_value(expr)
, который также похож на:
co_await sock.coro_write(expr)
Я открыл заголовок генератора, поставляемый с Visual Studio 2019, и увидел, что он также сохранил адрес параметра в yield_value
, и позже извлек его через generator::iterator::operator *()
в месте вызова после приостановки сопрограммы:
struct promise_type {
_Ty const* _CurrentValue;
auto yield_value(_Ty const& _Value) {
_CurrentValue = _STD addressof(_Value);
return suspend_always{};
}
}
struct iterator {
_NODISCARD reference operator*() const {
return *_Coro.promise()._CurrentValue;
}
_NODISCARD pointer operator->() const {
return _Coro.promise()._CurrentValue;
}
}
. Исходя из этого, я пришел к выводу, что параметр, переданный функции, которая возвращает ожидание, используемое с co_await
, также будет оставаться действительным до тех пор, пока сопрограмма не будет возобновлена или разрушен, это правда? или это специально для yield_value
в виде обещания?