Как правильно использовать std :: bind с std :: unique_ptr - PullRequest
0 голосов
/ 06 июня 2019

Я пытаюсь std::bind функций класса в комбинации std::unique_ptr, и у меня много проблем с тем, чтобы заставить его работать

Сначала у меня есть два класса

class simpleClass{
    public:
        simpleClass(int x){
            this->simpleNumber = x;
        }

        int simpleNumber;

        simpleClass(const simpleClass &toBeClone){
            this->simpleNumber = toBeClone.simpleNumber;
        }
        simpleClass clone(){
            simpleClass *cloned = new simpleClass(*this);
            return *cloned;
        }
};
class   className{
    public:
        className(doube input){
            this->someVariable = input;
        }

        void someFunction(std::vector<double> x, double c, std::unique_ptr<simpleClass> &inputClass, std::vector<double> &output){
            std::vector<double> tempOutput;
            for(int i = 0; i<x.size(); i++){
                tempOutput.push_back(x[i] + c * this->someVariable + inputClass->simpleNumber);
            }
            output = tempOutput;
        }

        double someVariable;

        className(const className &toBeClone){
            this->someVariable = toBeClone.someVariable;
        }

        className clone(){
            className *cloned = new className(*this);
            return *cloned;
        }
};

Они оба являются стандартным классом, но я также реализую функцию клона для дублирования инициализированного класса.При клонировании мне нужно убедиться, что исходный класс и клонированный класс указывают на разные адреса.Поэтому я использую std::unique_ptr для обеспечения этого.

Основная функция, которая также показывает, как я "клонирую"

int main(){
    className testSubject(5);
    std::vector<std::unique_ptr<className>> lotsOfTestSubject;

    simpleClass easyClass(1);
    std::vector<std::unique_ptr<simpleClass>> manyEasyClass;


    for(int i = 0; i<10; i++){
        std::unique_ptr<className> tempClass(new className(testSubject.clone()))
        lotsOfTestSubject.push_back(std::move(tempClass));    

        std::unique_ptr<simpleClass> tempEasyClass(new simpleClass(easyClass.clone()))
        manyEasyClass.push_back(std::move(tempEasyClass));    
    }

    std::vector<std::vector<<double>> X; //already loaded with numbers
    double C = 2;
    std::vector<std::vector<<double>> OUT;

    for(int i = 0; i<10; i++){
        std::vector<double> tempOUT;
        lotsOfTestSubject[i]->someFunction(X[i], C, manyEasyClass[i], tempOUT);
        OUT.push_back(tempOUT);

        //Here if I want to bind
        /*
           std::bind(&className::someFunction, lotsOfTestSubject[i], X[i], C, manyEasyClass[i], tempOUT);
        */
    }
    return 0;
}

Причина, по которой я "клонирую", заключается в том, что оба simpleClass и className занимают много времени для построения в моей реализации, и мне нужно много из них.И поскольку многие из них будут инициализированы с одинаковыми параметрами, я подумал, что это самый простой способ сделать это.

Приведенный выше код работает, но я пытаюсь повысить скорость цикла.Следующая строка - это место, где происходит большая часть вычислений.

lotsOfTestSubject[i]->someFunction(X[i], C, manyEasyClass[i], tempOUT);

Поэтому я пытаюсь использовать потоки для делегирования работы, и, насколько я знаю, мне сначала нужно std::bind.Итак, я попробовал

std::bind(&className::someFunction, lotsOfTestSubject[i], X[i], C, manyEasyClass[i], tempOUT);

Но компилятор печатает ошибку вот так

/usr/include/c++/5/tuple|206|  recursively required from ‘constexpr std::_Tuple_impl<_Idx, _Head, _Tail ...>::_Tuple_impl(const _Head&, const _Tail& ...) [with long unsigned int _Idx = 1ul; _Head = std::vector<double>; _Tail = {double, std::unique_ptr<simpleClass, std::default_delete<simpleClass> >, std::unique_ptr<simpleClass, std::default_delete<simpleClass> >, std::vector<double>}]’|
/usr/include/c++/5/tuple|108|error: use of deleted function ‘std::unique_ptr<_Tp, _Dp>::unique_ptr(const std::unique_ptr<_Tp, _Dp>&) [with _Tp = className; _Dp = std::default_delete<className>]’|

Я понятия не имею, что это значит, так как я только начал заниматься самообучением c ++.Любые отзывы и рекомендации очень ценятся.Я использую c ++ 11 и g ++ (Ubuntu 5.4.0-6ubuntu1 ~ 16.04.11) 5.4.0 20160609

Обновление

Спасибо @ rafix07, попробовал вашРешение и оно работает отлично.но потом я попытался сделать

auto theBinded = std::bind(&className::someFunction, &lotsOfTestSubject[i], 
          X[i], C, std::ref(manyEasyClass[i]), tempOUT);
std::thread testThread(theBinded);

и, в конце концов, захотел testThread.join() Но компилятор говорит:

error: pointer to member type ‘void (className::)(std::vector<double>, double, std::unique_ptr<simpleClass>&, std::vector<double>&)’ incompatible with object type ‘std::unique_ptr<className>’|

@ kmdreko Спасибо за указание!Я еще не заметил утечки памяти, но исправлю.Я просто использую это?

std::unique_ptr<className> tempClass = new className(testSubject);

1 Ответ

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

EDIT

Если вы хотите вызвать someFunction для экземпляра, хранящегося в lotsOfTestSubject, вам нужно передать указатель на className объект, для которого будет вызван этот метод, поэтому строка ниже

std::bind(&className::someFunction, lotsOfTestSubject[i]

следует заменить на:

auto theBinded = std::bind(&className::someFunction, lotsOfTestSubject[i].get(), 
                                                                          ^^^          

Второе изменение заключается в использовании std::ref для передачи исходного экземпляра unique_ptr из manyEasyClass вместо его копии.std::bind всегда копирует или перемещает свои аргументы ( см. Ссылку ), но unique_ptr не подлежит копированию, поэтому сборка не удалась.

Итак, выглядит фиксированная строка:

auto theBinded = std::bind(&className::someFunction, lotsOfTestSubject[i].get(), 
      X[i], C, std::ref(manyEasyClass[i]), std::ref(tempOUT));

tempOUT также должно быть передано std::ref, потому что вы хотите изменить этот вектор с помощью оператора вызова () для функтора, созданного bind.

LIVE DEMO

...