C++ 传递给返回awaitable的函数的临时值在使用co_await的暂停点之后是否仍然有效
我在基于windows io完成端口的异步套接字类中添加对协同路由ts的支持。 如果没有协同路由,io可以这样做:C++ 传递给返回awaitable的函数的临时值在使用co_await的暂停点之后是否仍然有效,c++,coroutine,c++20,c++-coroutine,C++,Coroutine,C++20,C++ Coroutine,我在基于windows io完成端口的异步套接字类中添加对协同路由ts的支持。 如果没有协同路由,io可以这样做: sock.async_write(io::buffer(somebuff), [](auto&& ... args){ /* in handler */ }); 或 第一个副本不会造成损害,但第二个副本会造成损害,因为它将触发堆分配并复制向量内容 因此,我正在寻找解决方案,在阅读本页时,我发现: 典型的生成器的yield_值将其参数存储(复制/移动或仅存储其地址,
sock.async_write(io::buffer(somebuff), [](auto&& ... args){ /* in handler */ });
或
第一个副本不会造成损害,但第二个副本会造成损害,因为它将触发堆分配并复制向量内容
因此,我正在寻找解决方案,在阅读本页时,我发现:
典型的生成器的yield_值将其参数存储(复制/移动或仅存储其地址,因为参数的生存期跨越co_wait中的挂起点)到生成器对象中,并返回std::suspend_always,将控制权转移到调用方/恢复方
从同一页上可以看出,co\u产量
表达式相当于:
co_await promise.yield_value(expr)
这也类似于:
co_await sock.coro_write(expr)
我打开了visual studio 2019附带的生成器标头,看到它还将参数的地址存储到yield_value
,并在协同路由暂停后通过调用方站点中的生成器::迭代器::运算符*()
检索到它:
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
一起使用的等待器的函数的参数也将保持有效,直到恢复或取消协同路由,对吗?或者,这是专用于使用visual studio 2019 16.4.4测试的承诺类型中的收益率\u值
,,并且可以正常工作。事实上,传递的参数和转换的参数也保持有效,直到await\u resume
返回或await\u suspend
由于抛出异常或返回值表示无意暂停协同路由而未暂停后,才会被销毁
这就是我所做的:
1-为缓冲区类型创建析构函数,如下所示:
~const_buffer()
{
std::cout << __FUNCSIG__ << std::endl;
}
~mutable_buffer()
{
std::cout << __FUNCSIG__ << std::endl;
}
// mutable to const conversion
operator const_buffer() const noexcept { return { data_, size_ }; }
3-在wait_resume
的末尾,我打印了一张类似的照片
4-这是传递的缓冲区参数的类型:
awaitable coro_read(const io::mutable_buffer& buff, transfer_flags);
awaitable coro_write(const io::const_buffer& buff, transfer_flags);
template </**/>
awaitable::awaitable(const io::mutable_buffer& buff) { /*store in ptr*/ }
template </**/>
awaitale::awaitable(const io::const_buffer& buff) { /*store in ptr*/ }
7-服务器输出:
issue_coro_op -> read
await_resume -> read
~mutable_buffer -> read
>> some message
issue_coro_op -> write
await_resume -> write
~const_buffer -> write
~mutable_buffer -> write
注意,io::buffer
返回io::mutable_buffer
,在写操作中将其转换为io::const_buffer
,这两个缓冲区在恢复后保持有效,然后按相反顺序销毁
我无法使用clang cl 8进行测试,因为它在编译代码时崩溃!以及mingw-w64和gcc 8,后者还不支持协同路由
void issue_coro_op(awaitable& a)
{
// use the awaitable to issue the op
std::cout << "~ " << __FUNCSIG__ << std::endl;
}
awaitable coro_read(const io::mutable_buffer& buff, transfer_flags);
awaitable coro_write(const io::const_buffer& buff, transfer_flags);
template </**/>
awaitable::awaitable(const io::mutable_buffer& buff) { /*store in ptr*/ }
template </**/>
awaitale::awaitable(const io::const_buffer& buff) { /*store in ptr*/ }
io::task<> run_session(tcp::async_socket sock)
{
char buff[1024];
string server_msg;
try
{
for (;;)
{
auto n = co_await sock.coro_read(io::buffer(buff), transfer_flags::unspecified);
if (buff[n - 1] == '\n')
--n;
cout << ">> " << string_view{ buff, n } << endl;
server_msg = fmt::format("{{ server message : {} }}\n", string_view{ buff, n });
n = co_await sock.coro_write(io::buffer(server_msg), transfer_flags::unspecified);
}
}
catch (std::exception & ex)
{
cout << "[!] a client has disconnected : " << ex.what() << endl;
}
}
nc localhost 4567
some message
{ server message : some message }
issue_coro_op -> read
await_resume -> read
~mutable_buffer -> read
>> some message
issue_coro_op -> write
await_resume -> write
~const_buffer -> write
~mutable_buffer -> write