C++ 11 の機能と共に boost::asio を使用して調査しています。特に、ここにある「async_tcp_echo_server.cpp」という例に焦点を当てています(コードは質問の最後にも示されています):
私の質問はクラスのtcp::socket
メンバーsocket_
に関係しています。クラスserver
のdo_accept()
メソッドでは、に渡されます。(asio のドキュメントによると、最初のパラメーターとして、接続を受け入れるには が必要です。) これまでのところ、とても良いです。server
socket_
async_accept()
async_accept()
socket
次のパラメーターである非同期受け入れ操作のコールバックは、ラムダ関数です。ラムダの本体は新しいsession
オブジェクトを構築し、そのコンストラクターも同じ を必要としsocket
ます。興味深いことに、socket
オブジェクトはコピーできません。そのため、この例では、socket_
オブジェクトのメンバーであるserver
オブジェクトが を使用して渡されstd::move()
ます。
「唯一の」socket_
オブジェクト (オブジェクトの「永続的な」メンバーserver
) がオブジェクトに「移動」されることを理解していsession
ます。結構です --socket
オブジェクトはコピーされませんが、移動されます -- みんな幸せです。
しかし、次に を呼び出すとどうなるasync_accept()
でしょうか。以前に移動された同じsocket_
(のメンバーserver
) が再度渡されましたか? メンバーを「移動」すると、何が残されますか? socket
無制限のオブジェクトの魔法の泉はありますか?
それとも、ここで実際に明らかではない何かが起こっているのでしょうか? がsocket
に移動されるsession
と、「取り残された/移動された」オブジェクト (socket_
のメンバーserver
)の内容は、「新しい」オブジェクト自体の「まだ構築されていない」メンバーの内容と交換されますか? 私は理にかなっていますか?session
socket_
概要
コードは以下です。プログラムの流れはかなり単純です。main()
単一のserver
オブジェクトを構築します。はserver
を繰り返し呼び出しますasync_accept()
。各async_accept()
コールバックは新しいsession
オブジェクトを作成し、それぞれが (fresh?) で構築されますsocket
。(single)socket
の同じメンバーから単純に (繰り返し) 「移動」された場合、すべての「新鮮な」オブジェクトはどこから来るのでしょうか?socket_
server
#include <cstdlib>
#include <iostream>
#include <memory>
#include <utility>
#include <boost/asio.hpp>
using boost::asio::ip::tcp;
class session
: public std::enable_shared_from_this<session>
{
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& 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<session>( std::move( socket_ ) )->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 << "Usage: async_tcp_echo_server <port>\n";
return 1;
}
boost::asio::io_service io_service;
server s( io_service, std::atoi( argv[1] ) );
io_service.run();
} catch( std::exception& e ) {
std::cerr << "Exception: " << e.what() << "\n";
}
return 0;
}