2014-01-10 92 views
27

嗯,我有一個使用std :: thread將數據傳遞到線程的問題。我認爲我理解了拷貝構造函數等的一般語義,但似乎我並不十分把握這個問題。我有一個名爲日誌簡單的類,隱藏了它的拷貝構造函數正是如此:std ::線程通過引用調用通過複製構造函數

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

你可以看到,主調用函數服務器,並傳遞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"); 
} 

我得到一個編譯錯誤,當我試圖通過記錄器(或插座)的線程通過參考,但它傳遞的時候我沒有得到錯誤會話()通過引用

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)'be ING編譯

1>使用

1> [

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會超越線程。

+3

這工作很好,謝謝。我不知道std :: ref()。 – xaviersjs

4

我得到一個編譯錯誤,當我試圖通過參考

這是不夠的線程的入口函數取引用類型通過記錄器(或插座)的線程:在線程對象本身按值取其參數。這是因爲你通常需要一個單獨的線程中的對象的副本。

爲了解決這個問題,您可以通過std::ref(logger),這是一個reference wrapper隱藏引用語義下的可複製對象。

相關問題