Note that there are some explanatory texts on larger screens.

plurals
  1. PORepeated std::move on an boost::asio socket object in C++11
    primarykey
    data
    text
    <p>I am exploring using boost::asio along with C++11 features. In particular, I am focusing on an example called "async_tcp_echo_server.cpp", located here (code is also shown at the end of my question):</p> <p><a href="http://www.boost.org/doc/libs/1_54_0/doc/html/boost_asio/example/cpp11/echo/async_tcp_echo_server.cpp" rel="noreferrer">http://www.boost.org/doc/libs/1_54_0/doc/html/boost_asio/example/cpp11/echo/async_tcp_echo_server.cpp</a></p> <p>My question involves the <code>tcp::socket</code> member <code>socket_</code> of the <code>server</code> class. In the <code>do_accept()</code> method of the <code>server</code> class, <code>socket_</code> is passed to <code>async_accept()</code>. (According to the asio documentation, <code>async_accept()</code> requires, as its first parameter, the <code>socket</code> to accept the connection into.) So far, so good.</p> <p>The next parameter, the callback for the asynchronous accept operation, is a lambda function. The body of the lambda constructs a new <code>session</code> object, whose constructor also needs the same <code>socket</code>. Interestingly, <code>socket</code> objects cannot be copied; so in the example, the <code>socket_</code> object, which is a member of the <code>server</code> object, is passed using <code>std::move()</code>.</p> <p>I understand that the "one and only" <code>socket_</code> object (which is a "permanent" member of the <code>server</code> object) is "moved" into the <code>session</code> object. Fine -- <code>socket</code> object is not copied, but moved -- everybody's happy.</p> <p>But what happens on the next call to <code>async_accept()</code>? Is the same <code>socket_</code> (member of <code>server</code>), that was previously moved, passed in again? When we "move" a member, what is left behind? Is there a magical fountain of unlimited <code>socket</code> objects?</p> <p>Or is something really less-than-obvious happening here? When the <code>socket</code> is moved into the <code>session</code>, is the contents of the "left behind/moved from" object (<code>socket_</code> member of <code>server</code>) <em>swapped</em> with the contents of the "new" <code>session</code> object's own "not-yet-constructed" <code>socket_</code> member? Am I even making sense?</p> <h1>Summary</h1> <p>Code is below. Program flow is fairly simple. <code>main()</code> constructs a single <code>server</code> object. The <code>server</code> makes repeated calls to <code>async_accept()</code>. Each <code>async_accept()</code> callback creates a new <code>session</code> object, each constructed with a (fresh?) <code>socket</code>. Where do all the "fresh" <code>socket</code> objects come from, if they are simply (repeatedly) "moved" from the same <code>socket_</code> member in the (single) <code>server</code>?</p> <pre><code>#include &lt;cstdlib&gt; #include &lt;iostream&gt; #include &lt;memory&gt; #include &lt;utility&gt; #include &lt;boost/asio.hpp&gt; using boost::asio::ip::tcp; class session : public std::enable_shared_from_this&lt;session&gt; { public: session( tcp::socket socket ) : socket_( std::move( socket ) ) {} void start() { do_read(); } private: void do_read() { auto self( shared_from_this() ); socket_.async_read_some( boost::asio::buffer( data_, max_length ), [this, self]( boost::system::error_code ec, std::size_t length ) { if( !ec ) { do_write( length ); } } ); } void do_write( std::size_t length ) { auto self( shared_from_this() ); boost::asio::async_write( socket_, boost::asio::buffer( data_, length ), [this, self]( boost::system::error_code ec, std::size_t /*length*/ ) { if( !ec ) { do_read(); } } ); } tcp::socket socket_; enum { max_length = 1024 }; char data_[max_length]; }; class server { public: server( boost::asio::io_service&amp; io_service, short port ) : acceptor_( io_service, tcp::endpoint( tcp::v4(), port ) ) , socket_( io_service ) { do_accept(); } private: void do_accept() { acceptor_.async_accept( socket_, [this]( boost::system::error_code ec ) { if( !ec ) { std::make_shared&lt;session&gt;( std::move( socket_ ) )-&gt;start(); // is this a *swap* of socket_ ??? } do_accept(); } ); } tcp::acceptor acceptor_; tcp::socket socket_; }; int main( int argc, char* argv[] ) { try { if( argc != 2 ) { std::cerr &lt;&lt; "Usage: async_tcp_echo_server &lt;port&gt;\n"; return 1; } boost::asio::io_service io_service; server s( io_service, std::atoi( argv[1] ) ); io_service.run(); } catch( std::exception&amp; e ) { std::cerr &lt;&lt; "Exception: " &lt;&lt; e.what() &lt;&lt; "\n"; } return 0; } </code></pre>
    singulars
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload