C++ 使用std::unique_ptr和自定义deallocator包装原始指针

C++ 使用std::unique_ptr和自定义deallocator包装原始指针,c++,c,pointers,libsvm,unique-ptr,C++,C,Pointers,Libsvm,Unique Ptr,我试图将其用于某个复杂的应用程序,因为libsvm主要是一个C库,所以在加载某些数据后,必须使用自定义API函数来释放内存。我的意思是: struct svm_model *model; model = svm_load_model("path to model file"); //do some processing svm_free_and_destroy_model(&this->model); 以下是我使用的libsvm API函数的定义: struct svm_mo

我试图将其用于某个复杂的应用程序,因为libsvm主要是一个C库,所以在加载某些数据后,必须使用自定义API函数来释放内存。我的意思是:

struct svm_model *model;
model = svm_load_model("path to model file");

//do some processing

svm_free_and_destroy_model(&this->model);
以下是我使用的libsvm API函数的定义:

struct svm_model *svm_load_model(const char *model_file_name);
void svm_free_and_destroy_model(struct svm_model **model_ptr_ptr);
虽然这很好,但如果在处理模型数据时发生异常,那么最终会导致内存泄漏。为了防止这种情况,我将上述代码包装在一个类中,在构造函数中调用
svm\u load\u model
,在析构函数中调用
svm\u free\u和\u destroy\u model

现在,由于我们正处于智能指针的时代,我想变得更具创造性,并以某种方式将模型变量声明为
std::unique_ptr
,将指向
svm_free_和_destroy_model
的指针设置为自定义deallocator,但不幸的是,我不知道这样的事情是否可行。目前,我甚至无法使它编译,我只是在黑暗中拍摄。以下是我认为它应该如何工作:

std::unique_ptr<struct svm_model *, /* what should I add here? */ > model (svm_load_model("path to model file"), svm_free_and_destroy_model);
std::唯一的ptr模型(svm\u加载模型(“模型文件路径”)、svm\u释放模型和销毁模型);
唯一性的deleter\u ptr
应该是一个只接受指针的函数,而不是指向指针的指针。你可以试试:

void svm_deleter(svm_model*& model)
{
    svm_free_and_detroy_model(&model);
}

....

std::unique_ptr< svm_model, void(*)(svm_model*&) >(
    svm_load_model("path to model file")
  , &svm_deleter
);
void svm\u deleter(svm\u模型*&模型)
{
svm_-free_和_-detroy_模型(&model);
}
....
标准::唯一的_ptr(
svm_加载_模型(“模型文件路径”)
,&svm_删除器
);

std::unique\u ptr
的类型参数必须是
T
,而不是
T*
。使用lambda调用deleter函数

std::unique_ptr<svm_model, void(*)(svm_model *)> 
  p( svm_load_model( "path_to_model" ), 
     []( svm_model *mdl ) { 
       svm_free_and_detroy_model( &mdl ); 
     } 
   );

我理解你在C++中使用所有这些伟大的东西的动机,但是你以前的解决方案确实没有什么问题。有时,简单的答案是最好的。@markransom:他以前的解决方案的错误在于,模型在遇到异常时会泄漏。缺少使用try{…}catch(…){if(model)free(model);throw;}if(model)free(model)包装所有代码@K-ballo,我提到的解决方案是这个,它没有泄漏问题,因为它本质上是一个自制的智能指针:“为了防止这种情况,我将上述代码包装在一个类中,在构造函数中调用svm_load_model,在析构函数中调用svm_free_和_destroy_model。”@K-ballo不一定;OP说他已经为libsvm调用创建了一个RAII风格的包装器,可以防止泄漏。我个人认为,在使用C++ API时,该方法更有用,因为这样您就可以在RAII包装器中为所有模型处理调用创建转发函数。阅读示例很好,但当您真正尝试实现它们时,它会变得越来越难…我得到一个关于构造函数的第一个参数的错误:
error C2664:'std::unique_ptr::unique_ptr(svm_model*,void(u cdecl*const&)(svm_model*&))“:无法将参数1从“svm_模型*”转换为“svm_模型*”
@Mihai Todor:这是一个奇怪的错误。。。尝试从deleter函数和unique_ptr声明中删除引用。我认为这可能是由Visual Studio 2010编译器的某些问题引起的。。。这显然不是由deleter构造引起的。这是一个非常有趣的方法,但是我得到了一个关于构造函数的第一个参数的错误:
error C2664:'std::unique_ptr::unique_ptr(svm_model*,void(u cdecl*const&)(svm_model*&))“:无法将参数1从“svm_model*”转换为“svm_model*”
@MihaiTodor我在所有函数调用中使用
struct-svm_model
时都遇到类似错误,但可以通过删除
struct
来消除这些错误。”。。。不知道为什么。另外,我发布的解决方案在VS2010中也不起作用,因为它没有实现无状态lambda到函数指针的转换。我将添加另一个同样有效的解决方案。我认为您在这里犯了一个错误
[](svm\u load\u model*mdl)
,应该是
[](svm\u model*mdl)
,但它是有效的,也有意义。不过,我还有一个问题:如果svm_load_模型返回NULL会发生什么?我怎样才能测试它?@mihaitor Oops,复制粘贴错误,修复了它。在构造
unique\u ptr
@mihaitod之后,如果(!p){throw something;}
,可以使用
检查
nullptr
,或者成员变量
p
的类型将是
std::unique\u ptr
(或者
std::function
变量)。然后,您可以使用调用
svm\u load\u model
并提供deleter lambda在构造函数的初始化列表中初始化它。默认情况下,
unique\u ptr
初始化指向
nullptr
的内部指针,但我不确定自定义删除器的情况,VS2010编译成功。稍后要初始化它,您必须创建一个相同类型的临时
unique\u ptr
,并将其移动到
p
std::unique_ptr<svm_model, std::function<void(svm_model*)>>
  p( svm_load_model("path_to_model"), 
     []( svm_model *mdl ) {
       svm_free_and_destroy_model( &mdl );
     }
   );