COMオブジェクトでスマートポインタを使う

COMオブジェクトをスマートポインタで管理する方法のメモ書きです。

boost::shared_ptrはnew/deleteでインスタンス生成・開放するオブジェクトに対して使えますが、
COMオブジェクトのようにReleaseでオブジェクトを開放するものに対しては使えません。
そこで、boost::intrusive_ptrを使ってこれを実現します。

COMオブジェクトはIUnknownクラスの派生クラスとなるため、
IUnknownオブジェクトの参照カウンタをインクリメント・デクリメントする関数を以下のように定義します。

inline void intrusive_ptr_add_ref(IUnknown* p) { p->AddRef(); }
inline void intrusive_ptr_release(IUnknown* p) { p->Release(); }

これで、以下のようにintrusive_ptrをスマートポインタとして使えるようになります。

    // Direct3Dの初期化
    boost::intrusive_ptr<idirect3D9> pD3D =
        boost::intrusive_ptr<idirect3D9>(Direct3DCreate9(D3D_SDK_VERSION), false);

    if ( pD3D == NULL )
        throw std::runtime_error("Direct3Dの初期化に失敗しました。");

intrusive_ptrの使い方はshared_ptrとほぼ一緒です。
intrusive_ptrはshared_ptrと違い、参照カウンタを独自に持ちません。
したがって、COMオブジェクトのように既に参照カウンタを保持しているものに対して有効です。

C++11なら、COMオブジェクト専用のテンプレートクラスをusingで定義して使えば少し楽になります。

template <class T>
using ComPtr = boost::intrusive_ptr<t>;
    // Direct3Dの初期化
    ComPtr<idirect3D9> pD3D = ComPtr<idirect3D9>(Direct3DCreate9(D3D_SDK_VERSION), false);

    if ( pD3D == NULL )
        throw std::runtime_error("Direct3Dの初期化に失敗しました。");

COMオブジェクトに限らず、intrusive_ptrは参照カウンタの仕組みを既に持っているオブジェクトに対して使えるスマートポインタです。

■参考サイト
boost::intrusive_ptr
intrusive_ptr class template
C++ template typedef