boost::asio data owning `ConstBufferSequence`

boost::asio data owning `ConstBufferSequence`

本文关键字:owning ConstBufferSequence data asio boost      更新时间:2023-10-16

最后几天,我通过 asio 示例和 SO 上关于传递给 asios 启动函数的缓冲区的生命周期管理的其他问题阅读了很多。让我印象深刻的一个问题是,似乎没有"按值"解决方案,而是发起函数的调用者始终需要确保缓冲区在异步操作完成之前有效。通常,这是通过创建指向数据的共享指针并将其复制到处理程序来实现的。

就我而言,我已经在使用async_write重载,其中传递了一个ConstBufferSequence,其中包含例如下一条消息后跟下一条消息的大小。 即

auto message = std::make_shared<std::string>("hello");
auto size = std::make_shared<std::uint32_t>(message.size());
std::vector<asio::const_buffer> buffers = {asio::buffer(size, sizeof(*size)), asio::buffer(*message)};
asio::async_write(_socket, buffers, [message,size](...){...}); // prolong lifetime by coping shared ptrs.

因此,我正在考虑编写一个自定义Message类,该类既满足ConstBufferSequence概念,又拥有基础消息。我对代码进行了一些深入研究,发现在一个地方,缓冲区序列参数(最初通过const&传递到asio::async_write,然后通过const&传递,直到最终复制到asio::detail::write_op类的成员变量中。

所以这里是实际问题:

  • 这种方法可以用于火灾并忘记呼叫吗?这将在上面的 intos 中翻译如下:asio::async_write(_socket, Message("hello"),[](auto,auto){});

  • 组成操作的常量缓冲序列参数的生存期是否存在任何问题?

  • 这是个好主意吗?这显然违背了处理缓冲区生命周期管理的"正常"asio方式。

好奇你的想法 - 欢迎批评! ;-(

问候,马丁

我以前见过一个shared_buffer(我认为它在Asio文档/exmples中,稍后会搜索(。

此外,显然还有

boost::
  • asio::streambuf
  • 野兽缓冲区模型(flat_buffer、multi_buffer、vector_buffer(

当然,它只是将问题从所有权问题转移到终身问题。

让 Boost Asio 的缓冲区概念是"仅引用"或"视图语义"的好处是

  • 你永远不会遇到按值传递这些引用的终身问题,并且
  • 它们非常适合以正确的方式实现组合操作:无需对缓冲区组织的假设

找到了Asio的例子:这些天 https://www.boost.org/doc/libs/1_42_0/doc/html/boost_asio/example/buffers/reference_counted.cpp 住在

  • 示例/CPP03/缓冲区/reference_counted.cpp
  • 例子/CPP11/buffers/reference_counted.cpp

解决要点问题

这种方法可以用于火灾并忘记呼叫吗?这将在上面的 intos 中翻译如下:asio::async_write(_socket,Message("hello"(,{}(;

是的

组成操作的常量缓冲序列参数的生存期是否存在任何问题?

如果你管理得很好,那就不行了,无论如何这是一个要求

这是个好主意吗?这显然违背了处理缓冲区生命周期管理的"正常"asio方式。

取决于你如何做到这一点。如果您最终批量复制缓冲区,那将是昂贵的,并且不适用于某些异步操作(这要求缓冲区具有引用稳定性,这意味着:不更改地址,换句话说,不要四处移动(。

使用 move 语义授予许多缓冲区类型可能仍然能够提供此属性,但按值传递缓冲区的问题在于它们可能会创建多个副本,这

  • 要么不编译(因为它们不是右值(
  • 或者(如果您使用移动复制构造函数/赋值破解它(在使用移动自副本时可能会导致 UB。