2014-01-10 38 views
27

私はstd :: threadを使ってスレッドにデータを渡すことに問題があります。私はコピーコンストラクタの一般的な意味を理解していると思っていましたが、私はその問題をかなり把握していないようです。私は、それは以下のようなものをコピーコンストラクタです隠されたログと呼ばれる単純なクラスている:今、私はあなたがメインの機能サーバを呼び出して、渡していることがわかりますhttp://www.boost.org/doc/libs/1_55_0/doc/html/boost_asio/example/cpp11/echo/blocking_tcp_echo_server.cppstd :: thread渡しで参照渡しコピーコンストラクタ

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; 
} 

に大きく基づいて、メインを

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 &); 
} 

を持っていますIOService、portNumber、およびloggerです。私は参照することによりスレッドにロガー(またはソケット)を渡すしようとすると、私は、コンパイラのエラーを取得する

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"); 
} 

、これだけにそれを渡すときに、私はエラーを取得しない:ロガーはthusly、参照によって渡されますセッション()参照

static void session(tcp::socket *sock, Log &logger) 
{ 
    std::cout << " session() " << std::endl; 
} 

私は、参照がポインタを渡すのと同じことを正しく理解していると思っていました。つまり、コピーコンストラクタを呼び出さず、単にポインタを渡すだけで、ポインタではないように構文的に扱うことができます。

エラーC2248: 'ログイン::ログイン': 'ログイン::ログ'

の宣言を参照してください。プライベートメンバにアクセスすることはできませんが、クラスで 'ログ'

1> \ LOG.H(55)を宣言しました

1> \ LOG.H(28): 'ログ'

...

の宣言を参照してください。テンプレートのインスタンスを関数への参照を参照してください「のstd ::スレッド::スレッドを(_Fn、_V0_t & &、_V1_t) 'とする

1で>

1をコンパイルingが> [

1>のFn =無効( _cdecl *)(後押し:: ASIO :: IP :: TCPソケット:: *、ログ&) 、

1> _V0_t =後押し:: ASIO :: IP :: TCPソケット:: *、

1> _V1_t =ログ&

1>]

私はポインタを渡すためにそれを修正する場合は、すべてが私のコピーコンストラクタを呼び出し参照渡しされるのはなぜ

... 
     std::thread newThread(session, &sock, &logger); 
... 

static void session(tcp::socket *sock, Log *logger) 
{ 
    std::cout << " session() " << std::endl; 
} 

幸せです。 std :: threadのために何か特別なことが起こっていますか?私はコピーコンストラクタを誤解し、参照渡しをしましたか?

私がstd :: move()を使用しようとすると、同じように困惑するエラーが表示されます。私のVS2012がC++ 11を正しく実装していない可能性はありますか?

+0

参照渡しの情報はどこから取得しましたか? – zoska

+0

@zoska:彼は明らかに、「セッション」を参考にして、中間の呼び出しについて完全に忘れていると考えています。 –

+0

この質問はC++ 11とマークされているので、deleteキーワードを使ってコピーコンストラクタと代入演算子を非表示にすることができます。 –

答えて

53

std::threadは、引数を引数にとります。あなたはstd::reference_wrapperを使用してバック参照セマンティクスを取得することができます。

明らか
std::thread newThread(session, &sock, std::ref(logger)); 

あなたはloggerスレッドをoutlivesことを確認する必要があります。参照による

+3

それは美しく働いた、ありがとう。私はstd :: ref()について知らなかった。 – xaviersjs

4

私はロガー(またはソケット)を渡すしようとすると、私は、コンパイラのエラーを取得したスレッドには

スレッドのエントリポイント関数は参照型を取るためにそれは十分ではありません。スレッドオブジェクト自体はの値を引数としてとります。これは通常、オブジェクトのコピーを別のスレッドに入れたいからです。

これを回避するには、コピー可能オブジェクトの下にreference wrapperの非表示参照セマンティクスであるstd::ref(logger)を渡すことができます。