std :: thread passa per riferimento chiama costruttore copia

Bene, ho un problema con il passaggio di dati in un thread usando std :: thread. Pensavo di aver capito la semantica generale dei costruttori di copie, ecc. Ma sembra che non capisco del tutto il problema. Ho una semplice class chiamata Log che ha nascosto il suo costruttore di copie in questo modo:

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 listOfStreams; //disable copy constructor and assignment operator Log(const Log &); Log & operator=(const Log &); } 

ora ho un main basato pesantemente su 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; } 

È ansible visualizzare le chiamate principali al server delle funzioni e passa IOService, portNumber e logger. Il logger viene passato per riferimento, quindi:

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

Ricevo un errore del compilatore quando provo a passare il logger (o il socket) al thread per riferimento, ma non ottengo l’errore quando lo passo alla sessione () per riferimento

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

Ora pensavo di aver capito correttamente che un riferimento è lo stesso del passaggio di un puntatore. Cioè, non chiama il costruttore di copie, semplicemente passa il puntatore, che consente di trattare sintatticamente come se non fosse un puntatore.

errore C2248: ‘Log :: Log’: imansible accedere al membro privato dichiarato nella class ‘Log’

1> \ log.h (55): vedere la dichiarazione di ‘Log :: Log’

1> \ log.h (28): vedere la dichiarazione di ‘Log’

: consultare il riferimento all’istanza del modello di funzione ‘std :: thread :: thread (_Fn, _V0_t &&, _ V1_t)’ in fase di compilazione

1> con

1> [

1> Fn = void ( _cdecl *) (boost :: asio :: ip :: tcp :: socket *, Log &),

1> _V0_t = boost :: asio :: ip :: tcp :: socket *,

1> _V1_t = Log &

1>]

Tuttavia se lo modifico per passare un puntatore, tutto è felice

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

Perché sta passando per riferimento chiamando il mio costruttore di copie . C’è qualcosa di speciale qui a causa di std :: thread? Ho frainteso il costruttore di copia e passo per riferimento?

Ottengo un errore diverso ma ugualmente sconcertante se provo a usare std :: move () come è fatto nell’esempio. È ansible che il mio VS2012 non stia implementando correttamente C ++ 11?

std::thread prende i suoi argomenti in base al valore. Puoi recuperare la semantica di riferimento usando std::reference_wrapper :

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

Ovviamente è necessario assicurarsi che il logger sopravviva al thread.

Ricevo un errore del compilatore quando provo a passare il logger (o il socket) alla discussione per riferimento

Non è sufficiente che la funzione entrypoint del thread prenda un tipo di riferimento: l’object thread stesso prende i suoi argomenti in base al valore. Questo perché di solito vuoi una copia di oggetti in un thread separato.

Per aggirare questo problema, è ansible passare std::ref(logger) , che è un wrapper di riferimento che nasconde la semantica di riferimento sotto un object copiabile.