如何正确使用 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"是因为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);
编辑
如果你想调用 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
总是复制或移动其参数 (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() 来修改此向量
我正在尝试 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"是因为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);
编辑
如果你想调用 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
总是复制或移动其参数 (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
.