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 ) );
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を実装してみましょう。