The last days, I read alot through the asio examples and other questions here on SO regarding lifetime management of buffers passed to asios initiating functions. One issue that strikes me, is that there seems to be no "by value" solution, but instead the caller of the initiating function always needs to ensure that the buffers are valid until the async operation completes. Often this is achieved by creating shared pointers to the data and copying them into the handlers.
In my case I am already using the async_write
overload where a ConstBufferSequence
is passed in which holds e.g. the sizeof the next message followed by the next message. I.e.
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.
So I was thinking about writing a custom Message
class that fulfills the ConstBufferSequence
concept but also owns the underlying message. I dug a little into the code, and found, that at one place the buffer sequence argument, which is at first passed into asio::async_write
via const&
gets passed along via const&
until it finally is copied into a member variable of the asio::detail::write_op
class.
So here the actual question(s):
Can this approach work for a fire and forget call? This would translate above intos something like:
asio::async_write(_socket, Message("hello"),[](auto,auto){});
Are there any issues with the lifetime of the constbuffer sequence arguments w.r.t. composed operations?
Would this be a good idea? It obviously goes against the "normal" asio way of dealing with buffer lifetime management.
Curious about your thoughts - Criticism welcome! ;-)
Regards, Martin
I've seen a shared_buffer
before (I think it was in the Asio docs/exmples, will search later).
Furthermore there's obviously
Of course, it just moves the problem from an ownership issue into a life-time issue.
The upside of having Boost Asio's buffer concept being "ref-only" or "view-semantics" is that
Found the Asio example: https://www.boost.org/doc/libs/1_42_0/doc/html/boost_asio/example/buffers/reference_counted.cpp these days lives in
Can this approach work for a fire and forget call? This would translate above intos something like: asio::async_write(_socket, Message("hello"),{});
Yes
Are there any issues with the lifetime of the constbuffer sequence arguments w.r.t. composed operations?
Not if you manage it well, which is a requirement anyways
Would this be a good idea? It obviously goes against the "normal" asio way of dealing with buffer lifetime management.
Depends on how you do it. If you end up copying the buffer wholesale it would be costly, and also wouldn't work with some async operations (which require the buffer to have reference stability, meaning: not change address, in other words, not move around).
Granted with move-semantics many buffer types might still be able to offer this property, but the problem with buffers being passed by-value is that they might make multiple copies, which