Jim Hunziker
Jim Hunziker

Reputation: 15380

Why can this boost::asio::tcp::socket be re-used?

Below is some code from a boost::asio example. Why is it okay to move the socket_ member when constructing a chat_session if the recursive call at the bottom of the handler is going to hand this same tcp::socket out next time an accept happens? I thought that after a move operation, an object was no longer safe to use.

class chat_server
{
public:
  chat_server(boost::asio::io_service& io_service,
      const tcp::endpoint& endpoint)
    : acceptor_(io_service, endpoint),
      socket_(io_service)
  {
    do_accept();
  }

private:
  void do_accept()
  {
    acceptor_.async_accept(socket_,
        [this](boost::system::error_code ec)
        {
          if (!ec)
          {
            std::make_shared<chat_session>(std::move(socket_), room_)->start();
          }

          do_accept();
        });
  }

  tcp::acceptor acceptor_;
  tcp::socket socket_;
  chat_room room_;
};

Upvotes: 0

Views: 82

Answers (3)

Igor R.
Igor R.

Reputation: 15075

The Standard says that a "moved-from" object must be, at least, in a valid unspecified state.

The moved-from socket is safe to use, because its state is explicitly specified in the documentation:

Following the move, the moved-from object is in the same state as if constructed using the basic_stream_socket(io_context&) constructor.

Upvotes: 1

Alan Birtles
Alan Birtles

Reputation: 36389

The code is equivalent to doing the following:

some_class o;
while ( true )
{
  // assign a new instance of some_class to the o variable, calling o.bar() is valid
  o = some_class(...);
  foo(std::move(o));
  // o is no longer valid calling o.bar() would fail
}

The call to async_accept re-initialises the socket back to a valid value which can be used. A moved object is in an unspecified (but valid) state, it is up to the implementer of that object what that state is. In the case of an asio::tcp::socket the state is an uninitialised socket which can be used for new connections.

Upvotes: 3

Some programmer dude
Some programmer dude

Reputation: 409176

And you're correct, the socket object isn't usable after the move.

But the code calling your lambda will create a new socket and initialize your variable socket_ with that new socket. So the next time your lambda is called it's actually a different socket.

Upvotes: 1

Related Questions