shared_ptrの実装2

前回の続き

    smart_ptr< int > a( new int( 1 ) );
    smart_ptr< int > b = a;

このようにスマートポインタをコピーコンストラクタでそのままコピーすると、メンバのptrがそのままコピーされるので、new intで生成した実体を指すポインタが2つできてしまいますね。つまり2重delete。デストラクタで2回deleteされてエラーになります。



さて、ここで「所有権」について考えてみましょう(C++を勉強し始めたとき、所有権といわれてもサッパリでしたが)
この所有権というのは「誰がnew intで作られた領域を管理するのか」ということです。言い換えるとどの「スマートポインタがdeleteするのか」。

上の例ではa、b2つのポインタが1つの領域を指しているのでマズいわけです。

この所有権の管理の仕方によっていくつかのスマートポインタがあります。

  • auto_ptr(STL)
  • scoped_ptr(boost)
  • shared_ptr(boost)
  • weak_ptr(boost)
  • intrusive_ptr(boost)
  • smart_ptr(loki)
  • CComPtr(ATL)
  • ...

いろんなスマートポインタがあるんですね。

いくつか適当に解説を。

auto_ptr

コピー元からコピー先へ所有権が移動する。

    auto_ptr< int > a( new int( 1 ) );

最初はaに所有権がありますが

    auto_ptr< int > a( new int( 1 ) );
    auto_ptr< int > b = a;

コピーコンストラクタで所有権がbに移動します。コピー元(a)はnullになる。

実体をさすポインタが1つしか存在しないので、2重deleteにはなりません。
当然ですがコピー後のaを使うことはできません。

scoped_ptr

スコープ内のみで使用するためのスマートポインタ。コピー禁止。一度ポインタを格納すると必ずそのポインタが最後にdeleteする。

    {
        scoped_ptr< int > a( new int( 1 ) );
        aを使ってごにょごにょ;
        return、throwしても必ずdeleteされます。
    }

shared_ptr

実体が複数のポインタに「共有」されるスマートポインタ。実体の参照数がカウントされる。shared_ptrがコピーされるときに参照数をインクリメント、スコープから抜けるなどshared_ptrが破棄されるときに参照数がデクリメントされる。

    shared_ptr< int > a( new int( 100 ) );

最初は実体を指すポインタがaだけなので、参照数は1です。(参照数と重複するのでnew intの初期値を変えました)

ここで、shared_ptrをコピーすると、参照数が1増えます。

    shared_ptr< int > a( new int( 100 ) );
    shared_ptr< int > b = a;


new intの実体と参照数がshared_ptrによって共有されていますね。

参照数はshared_ptrが破棄されるとき(デストラクタ)にデクリメントされます。参照数が0になると実体がdeleteされます。ちょっと形を変えましょう。

    {
        shared_ptr< int > a( new int( 100 ) );  //参照数=1
        {
            shared_ptr< int > b = a;            //参照数=2
        }                                       //参照数=1
    }                                           //参照数=0 new intの実体がdeleteされる

waek_ptr

参照数を管理しない弱参照ポインタ。shared_ptrでは循環参照できませんが、weak_ptrを使えば可能ですよと。thisポインタからshared_ptrを取得したい場合などにも使えるようですね。(boost::enable_shared_from_thisを継承して、shared_from_this()を使用する。shared_ptr内で、SFINAEを使って実装しているようです)

intrusive_ptr

shared_ptrは自分で参照カウンタを管理していますが、intrusive_ptrは参照先で参照カウンタが管理されています。COMを利用する場合に使えそうですね。こちらもthisポインタからintrusive_ptrを作ることができます。

smart_ptr

lokiのスマートポインタ。ポリシーで動作を変えることができます。



他にもいろいろありますが、本題はshared_ptrなので、紹介は以上で。
後半、端折り過ぎですね。。。
次回から`shared_ptrを実装してみましょう。