2013-07-01 38 views
3

許多C API提供的是採取**p其除了釋放資源也設置指針NULL發佈功能。
我想換用一個定製刪除一個boost::shared_ptr例如C API調用。定製刪除了那個的shared_ptr指針預計的地址

下面是有關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變量,而不是一個,這使得代碼更容易發生錯誤。

我想使用一個單一的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()。歡迎更好的名稱建議!

下面的代碼:

#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

IMO應的typedef的boost :: shared_ptr的,因爲C++ 11有標準:: shared_ptr的,你會希望儘量減少升級編譯器時的遷移工作。 – Bathsheba

+0

@Bathsheba我只會保持命名空間清晰。批量替換boost :: shared_ptr到std :: shared_ptr可以在一秒內完成。而混合命名空間是危險的。 – billz

+0

@billz:很酷;只要我們考慮到移民問題。 – Bathsheba

回答

3

設置指向空是沒有意義的,因爲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拉姆達可用於:

[](AVFrame* ptr) { av_frame_free(&ptr); } 
+0

是的!這是我試圖做的,但不能完全得到它:-)。 Re:null,這確實是一個API的東西不是必需的。爲什麼使用'boost :: decay'而不僅僅是'Fun fun'?另外,Boost中已經沒有類似的東西了嗎? –

+0

@AdiShavit:['boost :: decay'](http://www.boost.org/doc/libs/1_53_0/libs/type_traits/doc/html/boost_typetraits/reference/decay.html)用於允許'樂趣'表示爲'void()',而不是必須使用'void(&)()'。這提供'boost :: function'用戶期望的相同語法。 –

+0

@Tanner Sansbury:對不起,我不明白你的答案。 –