多くの C API は**p
、リソースを解放するだけでなく、ポインターを に設定するを受け取る解放関数を提供しますNULL
。このような C API 呼び出しをカスタムのデリータで
ラップしたいと考えています。boost::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>
frame
外部から変更され、リークが発生する可能性があります。- 1 つではなく 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の回答。
- テンプレート ファンクターを作成するためのテンプレート関数が含まれているため、テンプレートの種類を指定する必要はありません。
- コードは に依存し
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.