3

许多 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>指针类型。
这种方法需要我分别持有资源和发布者,这有几个缺点:

  1. frame可能会在外部进行更改,从而导致泄漏。
  2. 它需要 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 的回答如下

  1. 它包含一个模板函数来创建模板函子,因此无需指定模板类型。
  2. 代码取决于boost::decay. 仅包含Fun fun;成员的版本也适用于我测试的简单案例。
  3. 我把名字改成了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.
4

1 回答 1

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); }
于 2013-07-01T12:38:58.210 回答