Well I have an issue with passing data into a thread using std::thread. I thought I understood the general semantics of copy constructors, etc. but it seems I don't quite grasp the problem. I have a simple class called Log that has hidden it's copy constructor thusly:
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 &); }
now I have a main based heavily on 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; }
You can see that main calls the function server and passes the IOService, portNumber and logger. The logger is passed by reference, thusly:
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"); }
I get a compiler error when I try to pass the logger (or the socket) to the thread by reference, but I do not get the error when passing it to the session() by reference
static void session(tcp::socket *sock, Log &logger) { std::cout << " session () " << std::endl; }
Now I thought that I understood correctly that a reference is the same as passing a pointer. That is, it does not call the copy constructor, it simply passes the pointer, which it lets you syntactically treat like it's not a pointer.
error C2248: 'Log::Log' : cannot access private member declared in class 'Log'
1> \log.h(55) : see declaration of 'Log::Log'
1> \log.h(28) : see declaration of 'Log'
...
: see reference to function template instantiation 'std::thread::thread(_Fn,_V0_t &&,_V1_t)' being compiled
1> with
1> [
1> Fn=void (_cdecl *)(boost::asio::ip::tcp::socket *,Log &),
1> _V0_t=boost::asio::ip::tcp::socket *,
1> _V1_t=Log &
1> ]
However if I modify it to pass a pointer, everything is happy
... std::thread newThread(session, &sock, &logger); ... static void session(tcp::socket *sock, Log *logger) { std::cout << " session () " << std::endl; }
Why is passing by reference calling my copy constructor. Is there something special happening here because of std::thread? Did I misunderstand the copy constructor and pass by reference?
I get a different but equally baffling error if I try to use std::move() as it is done in the example. Is it possible my VS2012 is not implementing C++11 correctly?
The point of "pass by reference" is to not make a copy as soon as Employee constructor is called, but only when you choose to initialize one of Employee's member with the Date passed.
Passing by value means that the parameter is copied into the function. That calls the copy constructor.
std::thread::operator= thread objects cannot be copied (2).
std::thread
takes its arguments by value. You can get reference semantics back by using std::reference_wrapper
:
std::thread newThread(session, &sock, std::ref(logger));
Obviously you must make sure that logger
outlives the thread.
I get a compiler error when I try to pass the logger (or the socket) to the thread by reference
It is not sufficient for the thread's entrypoint function to take a reference type: the thread object itself takes its arguments by value. This is because you usually want a copy of objects in a separate thread.
To get around this, you may pass std::ref(logger)
, which is a reference wrapper hiding reference semantics under a copyable object.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With