On Tue, 21 Sept 2021 at 17:22, Дмитрий Архипов via Boost < boost@lists.boost.org> wrote:
I haven't tested it, but this should probably work:
class session { public: session(tcp::socket socket) : session(std::make_unique
(std::move(socket))) {} void start() { do_read(); }
private: session(std::unique_ptr
impl) : impl_(std::move(impl)) {} void do_read() { auto& impl = *impl_; impl.socket.async_read_some( boost::asio::buffer(impl.data, max_length), [impl = std::move(impl_)](boost::system::error_code ec, std::size_t length) mutable { if (ec) { return; } session(std::move(impl)).do_write(length); }); }
void do_write(std::size_t length) { ... }
auto constexpr max_length = 1024; struct session_impl { session_impl(tcp::socket socket) : socket_(std::move(socket)) {} tcp::socket socket_; char data_[max_length]; }; };
...
session(std::move(socket)).start();
вт, 21 сент. 2021 г. в 18:02, Andrzej Krzemienski via Boost
: wt., 21 wrz 2021 o 16:50 Vinnie Falco via Boost
napisał(a): On Tue, Sep 21, 2021 at 7:34 AM Andrzej Krzemienski via Boost
wrote: I am not trying to solve any specific problem. It just strikes me
that a
shared_ptr is used in a demo example for the library. I was always of the opinion that a shared_ptr is often abused as a way of doing an ad-hoc GC.
Dear Andrzej, The use of shared_ptr in asio examples is largely an historic artefact from when the only completion type was only a function object, as in these examples. When using this style of asynchronous completion it is convenient to use some kind of reference-counted pointer to maintain the lifetime of IO objects such as sockets and their associated state, such as buffers. You don't *have* to use a reference-counting but you will need to ensure that the io objects and related buffers are not deleted while there are any asynchronous operations in progress against them. A shared_ptr happens to be the most convenient way of doing this when: - using continuation-passing style completion handlers, and - the lifetime of the io object is not deterministic. When using other styles of completion handling, such as the in-built coroutine support, reference counting can often become less important since code can be written in a "structured concurrency" style. In this way, asynchronous code can be laid out with the same structure as synchronous code. IO Object lifetimes then become governed by the coroutines that created them and are awaiting asynchronous operations against them.
In theory it should work since the echo protocol is half-duplex. What happens when you switch it to unique_ptr? Move-only handlers should work, but it is possible that Chris missed a place that is still doing a copy.
It breaks when I pass a callback (completion handler), for instance in:
void do_read() { auto self(shared_from_this()); socket_.async_read_some(boost::asio::buffer(data_, max_length), [this, *self*](boost::system::error_code ec, std::size_t length) { if (!ec) { do_write(length); } }); }
I would need to move the data inside the lambda capture, but if I do it, the subsequent call to socket_.async_read_some() is UB.
In order for this to work, the function `async_read_some()` would have to pass the socket back to my handler after it has performed the read.
Regards, &rzej;
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost