许多 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
可能会在外部进行更改,从而导致泄漏。- 它需要 2 个变量而不是 1 个变量,这使得代码更容易出错。
我想使用一个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 的回答如下。
- 它包含一个模板函数来创建模板函子,因此无需指定模板类型。
- 代码取决于
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.