shared_ptr的自定义删除器,需要指针的地址

时间:2013-07-01 10:48:40

标签: c++ boost shared-ptr

许多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个,这使得代码更容易出错。
  3. 我想使用单个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

    1. 它包含一个用于创建模板仿函数的模板函数,因此无需指定模板类型。
    2. 代码取决于boost::decay。一个只拥有Fun fun;成员的版本也适用于我测试过的简单案例。
    3. 我将名称更改为arg_ref_adaptor()。欢迎更好的名字建议!
    4. 以下是代码:

      #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.
      

1 个答案:

答案 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); }