HiveBrain v1.2.0
Get Started
← Back to all entries
patterncppMinor

Asynchronous connect() with one function call, using C++11 lambdas and Boost.Asio

Submitted by: @import:stackexchange-codereview··
0
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:

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.

  • 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.