Search code examples
c++socketsboostboost-asiomove

Can i have boost asio socket references in two different class instances?


I want to std::move(my_asio_socket) to the instance of some class. What if I do the same for an instance of some other class?

My purpose is to read_async in one class instance (let's say class A), and to execute write_async in the other (let's say class B). Because of some functionality implementations, I should do it this way.

Any suggestion would be nice.

UPDATED

it's not working properly as i expected.
The VS2015(vc14 compiler) shows me a kind of exception while debugging:

Microsoft C++ exception: boost::exception_detail::clone_impl<boost::exception_detail::error_info_injector<boost::system::system_error> > at memory location 0x02D8E3BC.

And after i hit continue in VS it show me that:

Run-Time Check Failure #0 - The value of ESP was not properly saved across a function call. This is usually a result of calling a function declared with one calling convention with a function pointer declared with a different calling convention.

As i said, i'm trying to boost::move (or std::move) the socket to other class instance. Here is a snippet of code of what i'm doing:

boost::shared_ptr<connection> new_connection_;//it's a field in my class,
//that's why i should reset it later
new_connection_.reset(new connection(std::move(socket_), io_service_));
new_connection_->start();

Now here is my connection ctor:

    connection::connection(boost::asio::ip::tcp::socket sock, boost::asio::io_service& io_ptr)
    : socket_(boost::move(sock)),
      io_ptr_(io_ptr),
      remote_ep(socket_.remote_endpoint()),
      //request_handler_(new request_handler(boost::move(socket_))),
      work(new boost::asio::io_service::work(io_ptr))
    {
      boost::shared_ptr<request_handler> req_ptr(new request_handler(boost::move(socket_)));
      request_handler_.swap(req_ptr);
    }

As you can see, i've tried initializing in the commented line, but it shows me the same result.
Here is the ctor for request_handler:

    request_handler::request_handler(boost::asio::ip::tcp::socket sock):
                                           socket_(boost::move(sock)){ }

And here is my method connection::start where the problem detects:

void connection::start()
{
    boost::asio::ip::tcp::socket::keep_alive kl(true);
    boost::asio::ip::tcp::socket::enable_connection_aborted eca(true);
    // here it breaks, when trying to set an option
    socket_.set_option(eca);
    socket_.set_option(kl);

    socket_.async_read_some(boost::asio::buffer(buffer_),
        boost::bind(&connection::handle_read, shared_from_this(),
            boost::asio::placeholders::error,
            boost::asio::placeholders::bytes_transferred));
}

This problem appears only when i use to move socket into the new instance of request_handler. If i'm not - then all goes okey. I can't understand what reason it could be, but seems like my socket_ (i declare it everywhere without any & or *) field from connection class is lost or kind of. But the debugger isn't showing me smthing like null, so i don't know what is it.


Solution

  • In general it is not guaranteed:

    Move assignment operators typically "steal" the resources held by the argument (e.g. pointers to dynamically-allocated objects, file descriptors, TCP sockets, I/O streams, running threads, etc.), rather than make copies of them, and leave the argument in some valid but otherwise indeterminate state. For example, move-assigning from a std::string or from a std::vector may result in the argument being left empty. However, this behaviour should not be relied upon.

    But according to the documentation for tcp::socket it is left in the same state:

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