patterncppMinor
Asynchronous connect() with one function call, using C++11 lambdas and Boost.Asio
Viewed 0 times
lambdasconnectasynchronouswithfunctionasiocalloneusingand
Problem
I've wanted to write a C++11 class for making IPv4 TCP connections and figured that it probably could be done with just one static function using some shared_ptr and lambda "magic". The following code seems to work - but I'm not entirely sure that it's safe and completely bug-free:
First of all, the
We'll create a
Then we'll just create our two callbacks. `resol
void Client::connect(boost::asio::io_service& io_service,
const std::string& address,
const std::string& port,
const Callbacks& callbacks)
{
using namespace boost::asio::ip;
std::shared_ptr socket = std::make_shared(io_service);
std::shared_ptr resolver = std::make_shared(io_service);
tcp::resolver::query query(address, port);
auto connectHandler = [socket, callbacks]
(const boost::system::error_code& errorCode, const tcp::resolver::iterator& it)
{
if (errorCode) {
callbacks.onConnectionError("Could not connect: " + errorCode.message());
} else if (it == tcp::resolver::iterator()) {
callbacks.onConnectionError("Could not connect!");
} else {
callbacks.onConnected(std::move(*socket));
}
};
auto resolveHandler = [socket, resolver, callbacks, connectHandler]
(const boost::system::error_code& errorCode, const tcp::resolver::iterator& it)
{
if (errorCode) {
callbacks.onConnectionError("Could not resolve address: " + errorCode.message());
} else {
boost::asio::async_connect(*socket, it, tcp::resolver::iterator(), connectHandler);
}
};
resolver->async_resolve(query, resolveHandler);
}First of all, the
Callbacks is just a struct with two callbacks: onConnected(tcp::socket) and onConnectionError(const std::string&).We'll create a
tcp::socket and a tcp::resolver inside shared_ptr since they need to "survive" this whole procedure and can't be copied (atleast not tcp::socket. It can however be moved, but not using C++11 lambdas (?)).Then we'll just create our two callbacks. `resol
Solution
Looks good to me.
Given what is posted there is not much else to comment about.
The only thing I may have done differently (but this is very subjective and I would not expect you to change if you prefer your technique).
Then prefixed all the boost stuff with
But as I say your technique is totally valid since you have bound the scope of the using declaration to the function. If I was code reviewing within your company I may have commented but I would not block your merge to mainline over it.
Given what is posted there is not much else to comment about.
- Object life-span: Looks good. (Though I recommend some unit-tests).
- Naming: Looks good.
- Style: Looks good. (Though personally I don't yet like '{' on the same line as other stuff).
The only thing I may have done differently (but this is very subjective and I would not expect you to change if you prefer your technique).
using namespace boost::asio::ip;
// I may have used
namespace BIP = boost::asio::ip;Then prefixed all the boost stuff with
BIP::. Just so I don't pollute the namespace.But as I say your technique is totally valid since you have bound the scope of the using declaration to the function. If I was code reviewing within your company I may have commented but I would not block your merge to mainline over it.
Code Snippets
using namespace boost::asio::ip;
// I may have used
namespace BIP = boost::asio::ip;Context
StackExchange Code Review Q#83032, answer score: 2
Revisions (0)
No revisions yet.