使用unique_ptr和自定义删除器包装C代码

时间:2013-10-03 18:15:11

标签: c++ opencv c++11 smart-pointers unique-ptr

我正在尝试在智能指针中将OpenCV的C-API(CvPOSITObject)中的对象包装起来。根据我的理解,它应该类似于以下内容:

unique_ptr<CvPOSITObject, decltype(cvReleasePOSITObject)> positObject;
positObject = unique_ptr<CvPOSITObject, decltype(cvReleasePOSITObject)>(cvCreatePOSITObject(param1, param2), cvReleasePOSITObject);

但是我收到编译错误,谷歌并没有真正帮助。

这两个函数的声明是:

CVAPI(CvPOSITObject*)  cvCreatePOSITObject( CvPoint3D32f* points, int point_count );
CVAPI(void)  cvReleasePOSITObject( CvPOSITObject**  posit_object );

我得到像

这样的东西
1>C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\include\memory(1227): error C2207: 'std::_Unique_ptr_base<_Ty,_Dx,_Empty_deleter>::_Mydel' : a member of a class template cannot acquire a function type
1>C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\include\memory(1322): warning C4180: qualifier applied to function type has no meaning; ignored
1>  Myfile.cpp
1>C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\include\memory(1221): warning C4180: qualifier applied to function type has no meaning; ignored
1>          C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\include\memory(1283) : see reference to class template instantiation 'std::_Unique_ptr_base<_Ty,_Dx,_Empty_deleter>' being compiled
1>          with
1>          [
1>              _Ty=CvPOSITObject,
1>              _Dx=void (CvPOSITObject **),
1>              _Empty_deleter=false
1>          ]
1>          C:\MyDir\Myfile.hpp(71) : see reference to class template instantiation 'std::unique_ptr<_Ty,_Dx>' being compiled
1>          with
1>          [
1>              _Ty=CvPOSITObject,
1>              _Dx=void (CvPOSITObject **)
1>          ]

我该如何正确地做到这一点?

2 个答案:

答案 0 :(得分:5)

您的代码存在两个问题。正如BenVoigt在answer中提到的那样,第一个是decltype不会触发从函数类型到指针到函数类型的隐式转换,因此必须明确地获取函数的地址。您的代码更改为

positObject = unique_ptr<CvPOSITObject, 
                         decltype(&cvReleasePOSITObject)>(
                         cvCreatePOSITObject(param1, param2), 
                         cvReleasePOSITObject);

但是,由于其他原因,现在无法编译,这将我们带入第二个问题。 cvReleasePOSITObject采用CvPOSITObject **类型的参数,但上面的unique_ptr会尝试使用CvPOSITObject *调用其删除器。要解决此问题,只需将lambda表达式用于删除器。

positObject = unique_ptr<CvPOSITObject, 
                         void(*)(CvPOSITObject *)>(
                         cvCreatePOSITObject(param1, param2), 
                         [](CvPOSITObject *p) { cvReleasePOSITObject(&p); });

如果要分隔unique_ptr的声明和初始化,有几个选项。第一个示例演示了如何为此使用lamda表达式。

auto deleter = [](int *p) {
    delete p;
};

int main()
{
    std::unique_ptr<int, decltype(deleter)> p(nullptr, deleter);    
    p.reset(new int(42));
}

你仍然必须将删除器实例传递给unique_ptr,否则它将尝试默认构造删除器,这会失败,因为从lambda表达式生成的闭包已经删除了默认构造函数(§5.1 .2 / 20 来自N3691)。

另一个选项是将删除器编写为函子,允许默认构造。

struct deleter
{
    void operator()(int *p) const
    {
        delete p;
    }
};

int main()
{
    std::unique_ptr<int, deleter> p;

    p.reset(new int(42));
}

答案 1 :(得分:3)

尝试

decltype(&cvReleasePOSITObject)

从函数名称到指向该函数的指针的隐式转换,但函数类型和函数指针类型不同,decltype不会导致隐式转换