具有模板化构造函数的C ++自定义线程包装程序导致将编译时间错误插入到std :: map中

时间:2019-06-28 00:48:25

标签: multithreading c++11 templates variadic-templates stdmap

我正在编写自己的基本游戏引擎,并且正在对其进行多线程处理。我创建了一个RawThread对象,该对象用消息队列等包装了std::thread。我想将这些RawThread映射到一个id(unsigned int)。因此,我尝试将一个插入std::map<unsigned int, RawThread>中,但是却遇到了一堆非常模棱两可的模板错误。如果我注释掉map.insert行,那么代码可以很好地编译,一切正常,但是我希望能够像在RawThread中尝试的那样,将main()插入地图。

我已经看了一个小时的代码,检查我的RawThread构造函数模板是否错误,或者是否正确使用了引用/指针,但是看不到问题。

#include <map>
#include <utility>
#include <thread>

class RawThread
{
public:

    RawThread(const RawThread& you)
    {
        *this = you;
    }



    ~RawThread()
    {
        delete mThread;
    }

    template<class Function, class... Args>
    RawThread(Function&&f, Args&&... args)
    {       
        mThread = new std::thread(std::forward<Function>(f),         
                                          std::forward<Args>(args)...);
    }

    const RawThread& operator=(const RawThread& in)
    {
        this->mThread = in.mThread;
        return *this;
    }

    void join()
    {
        mThread->join();
    }
    std::thread* mThread;
};



void hello(int x){while(true)++x;}

int main()
{
    int arg = 0;
    RawThread myThread(&hello, arg);
    unsigned int threadId = 0;
    std::map<unsigned int, RawThread> threadMap;
    threadMap.insert(std::make_pair(threadId, myThread));
    return 0;
}

我看到一个令人讨厌的错误,因此将其放在pastebin上:https://pastebin.com/9A4wN7kL

2 个答案:

答案 0 :(得分:1)

insert的问题是通过调用

制作了RawThread的副本
template<class Function, class... Args>
RawThread(Function&&f, Args&&... args)

然后FunctionRawThread的实例,而Args为空。 std::thread构造函数可以将object的实例作为其第一个参数,但是此实例的类必须提供operator()()作为线程的主体。您的班级缺少这一点。您可以添加它,然后代码就会编译。

class RawThread {
    //....
    void operator()() {}
};

但这不是您想要的。


对我来说,您应该以仅此类的一个实例保持活动RawThread指针的方式实现mThreadRawThread仅应移动,副本应被禁用。如果许多实例共享相同的mThread值,应该调用哪个实例来加入或删除该对象?

仅支持移动的版本可能是:

#include <map>
#include <utility>
#include <thread>

class RawThread {
public:
    ~RawThread()
    {
        if (mThread)
        {
            if (mThread->joinable())
                mThread->join();
            delete mThread;
        }
    }

    RawThread(RawThread&& theOther) {
        mThread = theOther.mThread;
        theOther.mThread = nullptr;
    }

    RawThread& operator=(RawThread&& theOther) {
        mThread = theOther.mThread;
        theOther.mThread = nullptr;
        return *this;        
    }

    template<class Function, class... Args>
    RawThread(Function&&f, Args&&... args) {
        mThread = new std::thread(std::forward<Function>(f),         
                                  std::forward<Args>(args)...);
    }

    void join() {
        mThread->join();
    }
    std::thread* mThread;
};

void hello(int x){while(true)++x;}

int main()
{
    int arg = 0;
    RawThread myThread(&hello, arg);
    unsigned int threadId = 0;
    std::map<unsigned int, RawThread> threadMap;
    threadMap.emplace(threadId,std::move(myThread)); // move object into map
    return 0;
}

答案 1 :(得分:0)

#include <map>
#include <utility>
#include <thread>
#include <memory>

class RawThread
{
public:

    template<class Function, class... Args>
    RawThread(Function&&f, Args&&... args)
    {
        mThread = std::make_shared<std::thread>(std::forward<Function>(f),
                                                std::forward<Args>(args)...);
    }
    RawThread(const RawThread &)=default;
    RawThread(RawThread &&)=default;
    RawThread()=delete;
    void join()
    {
        mThread->join();
    }

    std::shared_ptr<std::thread> mThread;
};



void hello(int x){while(true)++x;}

int main()
{
    int arg = 0;
    RawThread myThread(&hello, arg);
    unsigned int threadId = 0;
    std::map<unsigned int, RawThread> threadMap;
    //This line is wrong because it uses the constructor template instead of the copy constructor
    //threadMap.insert(std::make_pair(threadId, myThread);
    threadMap.insert(std::make_pair(threadId, (const RawThread &)myThread));//Good, it uses the copy constructor
    threadMap.insert(std::make_pair(threadId, std::move(myThread)));//Good, it uses the move constructor
    return 0;
}