std::thread を使用してスレッドにデータを渡す際に問題があります。コピーコンストラクタなどの一般的なセマンティクスは理解できたと思いますが、問題がよくわかっていないようです。したがって、コピーコンストラクターを非表示にした Log という単純なクラスがあります。
class Log
{
public:
Log(const char filename[], const bool outputToConsole = false);
virtual ~Log(void);
//modify behavior
void appendStream(std::ostream *);
//commit a new message
void commitStatus(const std::string str);
private:
//members
std::ofstream fileStream;
std::list<std::ostream *> listOfStreams;
//disable copy constructor and assignment operator
Log(const Log &);
Log & operator=(const Log &);
}
今、私はhttp://www.boost.org/doc/libs/1_55_0/doc/html/boost_asio/example/cpp11/echo/blocking_tcp_echo_server.cppに大きく基づいたメインを持っています
int main()
{
static int portNumber = 10000;
Log logger("ServerLog.txt", true);
logger.commitStatus("Log Test String");
try {
boost::asio::io_service ioService;
server(ioService, portNumber, logger);
}
catch (std::exception &e)
{
std::cerr << "Exception " << e.what() << std::endl;
logger.commitStatus(e.what());
}
return 0;
}
main が関数サーバーを呼び出し、IOService、portNumber、およびロガーを渡すことがわかります。ロガーは参照によって渡されるため、次のようになります。
using boost::asio::ip::tcp;
void server(boost::asio::io_service &ioService, unsigned int port, Log &logger)
{
logger.commitStatus("Server Start");
tcp::acceptor acc(ioService, tcp::endpoint(tcp::v4(), port));
while(true)
{
tcp::socket sock(ioService);
acc.accept(sock);
std::thread newThread(session, &sock, logger);
newThread.detach();
}
logger.commitStatus("Server closed");
}
ロガー (またはソケット) を参照によってスレッドに渡そうとするとコンパイラ エラーが発生しますが、参照によって session() に渡すとエラーは発生しません。
static void session(tcp::socket *sock, Log &logger)
{
std::cout << " session () " << std::endl;
}
これで、参照はポインタを渡すことと同じであることが正しく理解できたと思います。つまり、コピー コンストラクターを呼び出すのではなく、単にポインターを渡すだけで、構文的にはポインターではないかのように扱うことができます。
エラー C2248: 'Log::Log': クラス 'Log' で宣言されたプライベート メンバーにアクセスできません
1> \log.h(55) : 'Log::Log' の宣言を参照してください
1> \log.h(28) : 「ログ」の宣言を参照してください
...
: コンパイル中の関数テンプレートのインスタンス化 'std::thread::thread(_Fn,_V0_t &&,_V1_t)' への参照を参照してください
1>と
1> [
1> Fn=void ( _cdecl *)(boost::asio::ip::tcp::socket *,Log &),
1> _V0_t=boost::asio::ip::tcp::socket *,
1> _V1_t=ログ &
1> ]
ただし、ポインターを渡すように変更すると、すべてが満足します
...
std::thread newThread(session, &sock, &logger);
...
static void session(tcp::socket *sock, Log *logger)
{
std::cout << " session () " << std::endl;
}
参照渡しが私の copy constructor を呼び出すのはなぜですか。std::thread のために、ここで何か特別なことが起こっていますか? コピー コンストラクターと参照渡しを誤解していませんか?
例で行われているように std::move() を使用しようとすると、別の、しかし同様に不可解なエラーが発生します。VS2012 が C++11 を正しく実装していない可能性はありますか?