C++ 传递给返回awaitable的函数的临时值在使用co_await的暂停点之后是否仍然有效

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_值将其参数存储(复制/移动或仅存储其地址,

我在基于windows io完成端口的异步套接字类中添加对协同路由ts的支持。 如果没有协同路由,io可以这样做:

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