std :: thread通过引用调用复制构造函数

xav*_*sjs 28 c++ multithreading copy-constructor c++11 stdthread

我有一个使用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 &);
}
Run Code Online (Sandbox Code Playgroud)

现在我主要基于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;
}
Run Code Online (Sandbox Code Playgroud)

您可以看到main调用函数服务器并传递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");
}
Run Code Online (Sandbox Code Playgroud)

当我尝试通过引用将记录器(或套接字)传递给线程时,我收到编译器错误,但是在通过引用将它传递给session()时我没有收到错误

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

现在我认为我理解正确的引用与传递指针相同.也就是说,它不会调用复制构造函数,它只是传递指针,它允许你在语法上对待它,就像它不是指针一样.

错误C2248:'Log :: Log':无法访问类'Log'中声明的私有成员

1>\log.h(55):查看'Log :: Log'的声明

1>\log.h(28):查看'Log'的声明

...

:请参阅正在编译的函数模板实例化'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;
}
Run Code Online (Sandbox Code Playgroud)

为什么通过引用传递我的复制构造函数.因为std :: thread,这里有什么特别的事吗?我是否误解了复制构造函数并通过引用传递?

如果我尝试使用std :: move(),我会得到一个不同但同样令人困惑的错误,就像在示例中所做的那样.我的VS2012可能没有正确实现C++ 11吗?

jua*_*nza 58

std::thread以价值来看待它的论点.您可以使用std::reference_wrapper以下方法获取引用语义:

std::thread newThread(session, &sock, std::ref(logger));
Run Code Online (Sandbox Code Playgroud)

显然你必须确保logger线程超过线程.

  • 这非常有效,谢谢.我不知道std :: ref(). (3认同)

Lig*_*ica 6

当我尝试通过引用将记录器(或套接字)传递给线程时出现编译器错误

线程的入口点函数采用引用类型是不够的:线程对象本身按值获取其参数。这是因为您通常需要一个单独线程中的对象副本。

为了解决这个问题,您可以传递std::ref(logger),它是一个引用包装器,将引用语义隐藏在可复制对象下。