Boost logo

Boost Users :

Subject: Re: [Boost-users] [Asio/Beast] Any non-obvious reasons for no bind_executor_and_allocator?
From: Sorin Fetche (sorin.fetche_at_[hidden])
Date: 2018-12-23 19:58:24


On Thu, Dec 20, 2018 at 9:25 AM Sorin Fetche wrote:
>
> On Wed, Dec 19, 2018 at 10:24 PM Vinnie Falco wrote:
> >
> > Have you considered writing a base class which takes ownership of the
> > user's completion handler and has the necessary hooks?
>
> <snip>
>
> Yes, the base class is a very good idea.
> It helps reduce the boilerplate in the composed operation and the risk
> of moving `this` before accessing things in it.
>
> Here's how its usage looks like to implement the composed operation:
> https://github.com/sorf/cpp-playground/blob/master/source/asio_echo_v2.cpp#L105
>
<snip>
> I still don't like the risk of moving `this` (or `self`) before
> members in the derived class are used to initiate the next operation
> (e.g. the echo_buffer).

With some additional work on the async state helper class, the example
composed asynchronous operation becomes pretty compact:

https://github.com/sorf/cpp-playground/blob/master/source/asio_echo_v3.cpp#L227

\code
template <typename StreamSocket, typename CompletionToken>
auto async_echo_rw(StreamSocket &socket, CompletionToken &&token)
    -> /*...*/ {

    struct state_data { /*...*/};
    using state_type = async_state</*...*/, state_data>;

    state_type state{std::move(completion.completion_handler),
        socket.get_executor(), socket, /*...*/};
    state_data *data = state.get();

    data->socket.async_read_some(
        asio::buffer(data->echo_buffer),
        state.wrap()([=, state = std::move(state)](
                error_code ec, std::size_t bytes) mutable {
                if (!ec) {
                    asio::async_write(data->socket, /*...*/);
                } else {
                    state.invoke(ec, bytes);
                }
        }));
    return completion.result.get();
}
\endcode

The helper class async_state addresses now both the risk of accessing
state after it has been moved and the using of the final handler to
allocate the internal state.
>From this perspective it is similar to beast::handler_ptr.
It also uses a bind_allocator utility similar to asio::bind_executor -
the thing that started this email thread.

I haven't tested it in depth yet to confirm that the final handler
allocator and executor are properly used in the internal operations,
but I would welcome feedback about this async_state helper class.
Would it worth trying to turn it into some general purpose utility?
Any caveats about asynchronous operations it left unaddressed?

https://github.com/sorf/cpp-playground/blob/master/source/asio_echo_v3.cpp#L84

Best regards,
Sorin


Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net