许多C API提供的释放函数采用**p
,除了释放资源外,还将指针设置为NULL
。
我想用boost::shared_ptr
包含自定义删除器的C API调用。
这是FFMPEG的一个例子:
AVFrame* frame = av_frame_alloc(); // allocate resource
// Do stuff with frame
av_frame_free(&frame) // free resource
为了利用RAII,我可以这样重写:
AVFrame* frame = av_frame_alloc();
boost::shared_ptr<AVFrame*> frame_releaser(&frame, av_frame_free);
// Do stuff with frame
请注意,shared_ptr<>
类型为<AVFrame*>
而非<AVFrame>
为指针类型。
这种方法要求我单独保存资源和发布者,这有几个缺点:
frame
可能会在外部发生变化,导致泄密。我想使用单个shared_ptr
变量来保存资源,在需要时释放它。
本着boost::ref
的精神,我正在寻找或使用泛型 address_of_arg_wrapper
作为删除器,这将允许我写这样的东西:
boost::shared_ptr<AVFrame> frame_handle(av_frame_alloc(), address_of_arg_wrapper(av_frame_free));
// Do stuff with frame_handle.get()
或
boost::shared_ptr<AVFrame> frame_handle(av_frame_alloc(), address_of_arg_wrapper<av_frame_free>());
// Do stuff with frame_handle.get()
包装器必须是通用的并接受任何指针(ref)类型,因此它可以与任何此类API函数一起使用。
我也不想指定类型。
Boost是否有这样的功能?
如果没有,那么如何编写这样的通用仿函数呢?
编辑 - 完整性解决方案:
此解决方案基于@R. Martinho Fernandes's answer below。
boost::decay
。一个只拥有Fun fun;
成员的版本也适用于我测试过的简单案例。arg_ref_adaptor()
。欢迎更好的名字建议!以下是代码:
#include <boost\type_traits\decay.hpp>
//////////////////////////////////////////////////////////////////////////
// Given a function or callable type 'fun', returns an object with
// a void operator(P ptr) that calls fun(&ptr)
// Useful for passing C API function as deleters to shared_ptr<> which require ** instead of *.
template <typename Fun>
struct arg_ref_adaptor_functor
{
public:
arg_ref_adaptor_functor(Fun fun): fun(fun) {}
template <typename P>
void operator()(P ptr)
{ fun(&ptr); }
private:
typename boost::decay<Fun>::type fun;
};
template <typename Fun>
inline arg_ref_adaptor_functor<Fun> arg_ref_adaptor(Fun fun)
{ return arg_ref_adaptor_functor<Fun>(fun); }
用法:
boost::shared_ptr<AVFrame> frame_handle(::av_frame_alloc()
,arg_ref_adaptor(::av_frame_free));
// Do stuff with frame_handle.get()
// The resource will be released using ::av_frame_free() when frame_handle
// goes out of scope.
答案 0 :(得分:3)
将指针设置为null是没有意义的,因为shared_ptr
已经保证指针在销毁后永远不会再次可见。所以代码只需要传递一个地址来取悦av_frame_free
函数。我建议简单地编写一个传递其参数地址的函数对象。
template <typename Fun>
struct address_of_arg_wrapper {
public:
address_of_arg_wrapper(Fun fun) : fun(fun) {}
template <typename P>
void operator()(P ptr) {
fun(&ptr);
}
private:
typename boost::decay<Fun>::type fun;
};
在C ++ 11中,可以使用lambda:
[](AVFrame* ptr) { av_frame_free(&ptr); }