C ++ Custom Thread Wrapper с Templatized Constructor вызывает ошибку времени компиляции для вставки в std :: map - PullRequest
0 голосов
/ 28 июня 2019

Я пишу свой собственный базовый игровой движок и многопоточность.Я создал объект RawThread, который оборачивает std::thread очередями сообщений и т. Д. Я хочу сопоставить эти RawThread с идентификатором (unsigned int).Поэтому я пытаюсь вставить один в std::map<unsigned int, RawThread>, но получаю кучу очень неоднозначных ошибок шаблона.Если я закомментирую строку map.insert, то код компилируется просто отлично, все работает, но я хочу иметь возможность вставить RawThread в карту, как это пыталось сделать в main().

Iв течение часа смотрел на этот код, проверяя, правильно ли я понял шаблон конструктора 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 ]

1 голос
/ 28 июня 2019

Проблема с insert заключается в том, что копия RawThread создается путем вызова

template<class Function, class... Args>
RawThread(Function&&f, Args&&... args)

затем Function является экземпляром RawThread, а Args пусто. Конструктор std::thread может принять экземпляр объекта в качестве первого параметра, но затем класс этого экземпляра должен предоставить operator()() в качестве тела потока. Ваш класс пропускает это. Вы можете добавить его, и код скомпилируется.

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

Но это не то, что вы хотите.


Для меня вы должны реализовать RawThread так, чтобы только один экземпляр этого класса поддерживал активный указатель mThread. RawThread следует только перемещать, копии следует отключать. В случае, когда многие экземпляры имеют одно и то же значение mThread, какой из них следует вызвать join или удалить этот объект?

Версия, которая поддерживает только перемещение, может быть:

#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;
}
0 голосов
/ 28 июня 2019
#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;
}
...