如何正确使用 std::bind 和 std::unique_ptr

How to use std::bind properly with std::unique_ptr

我正在尝试 std::bind class 功能与 std::unique_ptr 的组合,但我很难让它工作

首先我有两个classes

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;
        }
};

它们都是一些标准的 class,但我还实现了一个克隆函数来复制已初始化的 class。克隆时,我需要确保原始的 class 和克隆的 class 指向不同的地址。所以我使用 std::unique_ptr 来确保这一点。

这是主要功能,这也说明了我 "clone"

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;
}

我之所以"clone"是因为simpleClassclassName在我的实现中都需要大量的时间来构建,我需要的很多。而且由于其中许多将使用相同的参数进行初始化,我认为这是最简单的方法。

上面的代码有效,但我正在努力提高循环速度。下面一行是大部分计算发生的地方。

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);

编辑

如果你想调用 someFunction 存储在 lotsOfTestSubject 中的实例,你需要将指针传递给 className 将调用此方法的对象,所以下面的行

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

应替换为:

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

第二个更改是使用 std::ref 传递 unique_ptrmanyEasyClass 的原始实例,而不是其副本。 std::bind 总是复制或移动其参数 (see reference),但 unique_ptr 是 non-copyable,这就是编译失败的原因。

所以固定线看起来:

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

tempOUT 也必须由 std::ref 传递,因为您想通过在 bind.

创建的函子上调用 operator() 来修改此向量

LIVE DEMO