Почему этот boost::asio::tcp::socket можно использовать повторно?
Ниже приведен код из примера boost::asio. Почему это нормально, чтобы переместить socket_
член при построении chat_session
если рекурсивный вызов в нижней части обработчика собирается передать это же tcp::socket
в следующий раз, когда произойдет согласие? Я думал, что после операции перемещения объект больше не безопасен для использования.
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_;
};
3 ответа
Код эквивалентен выполнению следующего:
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
}
Призыв к async_accept
повторно инициализирует сокет обратно к допустимому значению, которое можно использовать. Перемещенный объект находится в неопределенном (но допустимом) состоянии, это зависит от разработчика этого объекта. В случае asio::tcp::socket
состояние - это неинициализированный сокет, который можно использовать для новых соединений.
Стандарт гласит, что "перемещенный" объект должен быть, по крайней мере, в допустимом неопределенном состоянии.
Перемещенный сокет безопасен в использовании, поскольку его состояние явно указано в документации:
И вы правы, объект сокета не может быть использован после перемещения.
Но код, вызывающий вашу лямбду, создаст новый сокет и инициализирует вашу переменную socket_
с этим новым сокетом. Поэтому в следующий раз, когда ваша лямбда будет вызвана, это будет другой сокет.