为什么我们可以在 acceptor_.async_accept 中重用移动的 socket_?

Why we can reuse a moved socket_ in acceptor_.async_accept?

参考:https://www.boost.org/doc/libs/1_35_0/doc/html/boost_asio/reference/basic_socket_acceptor/async_accept/overload1.html

boost::asio::ip::tcp::acceptor acceptor(io_service);
...
boost::asio::ip::tcp::socket socket(io_service); 
// you have to initialize socket with io_service first before 
//you can use it as a parameter on async_accept.
acceptor.async_accept(socket, accept_handler);

参考:

https://github.com/vinniefalco/CppCon2018/blob/master/listener.cpp

listener::  listener(
    net::io_context & ioc,
    tcp::endpoint endpoint,
    std::shared_ptr < shared_state >
    const & state): acceptor_(ioc), socket_(ioc), state_(state) {

// Accepts incoming connections and launches the sessions
class listener : public std::enable_shared_from_this<listener>
{
    tcp::acceptor acceptor_;
    tcp::socket socket_;
...
}

// Handle a connection
void listener::  on_accept(error_code ec) {
    if (ec)
      return fail(ec, "accept");
    else
      // Launch a new session for this connection
      std::make_shared < http_session > (
        std::move(socket_),                    // socket_ is moved here?
        state_) -> run();

    // Accept another connection
    acceptor_.async_accept(
      socket_,                                 // why we still can use it here?
      [self = shared_from_this()](error_code ec) {
        self -> on_accept(ec);
      });
  }

根据我的理解,std::move(socket_)允许编译器蚕食socket_。也就是说,原来由socket_(ioc)初始化的listener::socket_会变成未初始化的

问题> 如何将未初始化的 socket_ 赋给 acceptor_.async_accept

谢谢

这完全取决于类型的实现。

我们可以粗略地将移动的意图描述为“允许编译器蚕食”。但实际上,对于 user-defined 类型 我们 将不得不确切地告诉它如何去做。

在语言“原则”中,一个 moved-from 对象只能被假定为可以安全销毁,但在实践中,许多库会做出更宽松的保证(例如,保留所有不变量,或确保 moved-from 对象相当于一个新建的对象)。

确实,ASIO documents 这个:

Remarks

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