Reference: boost_1_78_0/doc/html/boost_asio/reference/ip__basic_resolver/async_resolve/overload1.html
template<
typename ResolveHandler = DEFAULT>
DEDUCED async_resolve(
const query & q,
ResolveHandler && handler = DEFAULT);
The handler to be called when the resolve operation completes. Copies will be made of the handler as required. The function signature of the handler must be:
void handler(
const boost::system::error_code& error, // Result of operation.
resolver::results_type results // Resolved endpoints as a range.
);
boost_1_78_0/libs/beast/example/websocket/client/async-ssl/websocket_client_async_ssl.cpp
void run(char const *host, char const *port, char const *text) {
...
resolver_.async_resolve(
host, port,
beast::bind_front_handler(&session::on_resolve, shared_from_this()));
}
void on_resolve(beast::error_code ec, tcp::resolver::results_type results) {
if (ec)
return fail(ec, "resolve");
// Set a timeout on the operation
beast::get_lowest_layer(ws_).expires_after(std::chrono::seconds(30));
// Make the connection on the IP address we get from a lookup
beast::get_lowest_layer(ws_).async_connect(
results,
beast::bind_front_handler(&session::on_connect, shared_from_this()));
}
Question 1> Why does the on_resolve
use the following function signature?
on_resolve(beast::error_code ec, tcp::resolver::results_type results)
As shown above, the first parameter(i.e. ec
) is taken as pass-by value. This happens almost in all other functions which take a beast::error_code
as an input parameter within sample code.
Instead of
on_resolve(const beast::error_code& ec, tcp::resolver::results_type results)
Question 2> Why doesn't the documentation suggest using the following instead?
on_resolve(const beast::error_code& ec, const tcp::resolver::results_type& results)
Thank you
It's a cultural difference between Asio and Beast if you will.
Rationale
In Asio, the standard "doctrine" is to take
error_code
by const&. In Beast, the standard practice is actually to pass by value, which is, IMO, howerror_code
is intended.In essence,
error_code
is just a tuple of(int, error_category const*)
which is trivially copied and therefore optimized. Passing by value allows compilers much more room for optimization, especially when inlining. A key factor is that value-arguments never create aliasing opportunities.(I can try to find a reference as I think some Beast devs are on record explaining this rationale.)
Why is it OK?
Any function that takes T by value is delegation-compatible with the requirement that it takes T by const reference, as long as T is copyable.
Other thoughts
There may have been historical reasons why Asio preferred, or even mandated
error_code const&
in the past, but as far as I am aware, any of these reasons are obsolete.