Reputation: 15380
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
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:
Upvotes: 1
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
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