std :: thread通过引用调用复制构造函数
那么我有一个使用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和logger。 logging器通过引用传递,因此:
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"); }
当我尝试通过引用将logging器(或套接字)传递给线程时,出现编译器错误,但是在通过引用将它传递给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 = Log&
1>]
但是,如果我修改它来传递指针,一切都很开心
... std::thread newThread(session, &sock, &logger); ... static void session(tcp::socket *sock, Log *logger) { std::cout << " session () " << std::endl; }
为什么通过引用传递我的拷贝构造函数 。 有什么特别的事情发生在这里,因为std ::线程? 我误解了复制构造函数,并通过引用?
如果我尝试在示例中使用std :: move(),我会得到一个不同但同样令人困惑的错误。 有没有可能我的VS2012没有正确实施C ++ 11?
std::thread
按值取其参数。 你可以通过使用std::reference_wrapper
来获得引用语义:
std::thread newThread(session, &sock, std::ref(logger));
显然你必须确保logger
超出线程。
当我尝试通过引用将logging器(或套接字)传递给线程时,出现编译器错误
线程的入口点函数采用一个引用types是不够的:线程对象本身通过值来引用它的参数。 这是因为你通常需要一个单独的线程中的对象的副本。
为了解决这个问题,你可以传递std::ref(logger)
,这是一个引用包装 std::ref(logger)
,它隐藏了可复制对象下的引用语义。