今回はweak_ptr。
weak_ptrは弱参照の概念のためのスマートポインタです。
shared_ptrでは循環参照の問題を解決できません。
#include <iostream> #include <memory> class Sample { public: Sample() {} ~Sample() {} std::shared_ptr<Sample> ptr; }; int main() { std::shared_ptr<Sample> p1(new Sample); std::shared_ptr<Sample> p2(new Sample); p1->ptr = p2; p2->ptr = p1; return 0; } // 解放されない
しかし、弱参照であるweak_ptrは参照カウントを行わないため、参照がある無しに関わらずスコープを抜けるとインスタンスを解放します。
#include <iostream> #include <memory> class Sample { public: Sample() {} ~Sample() {} std::weak_ptr<Sample> ptr; }; int main() { std::shared_ptr<Sample> p1(new Sample); { std::shared_ptr<Sample> p2(new Sample); p1->ptr = p2; p2->ptr = p1; } // p2のインスタンスは解放 return 0; } // p1のインスタンスは解放
もちろん、これはダングリング・ポインタを参照する危険が伴うことになりますが、次のようなチェックを行うことで防ぐことができます。
int main() { std::shared_ptr<Sample> p1(new Sample); { std::shared_ptr<Sample> p2(new Sample); p1->ptr = p2; p2->ptr = p1; } // p2のインスタンスは解放 /* lock()で生存を確認できる */ if( auto q = p1->ptr.lock() ){ /* p1->ptrはまだ生存(もちろんこのコードではここには来ない) */ } else{ /* p1->ptrは無効 */ } return 0; } // p1のインスタンスは解放
ちなみにlock()はshared_ptrを返すメンバ関数です。
weak_ptrは生ポインタの特性にとてもよく似ていますが、スコープを抜けるときに確実にインスタンスの解放を行うため、生ポインタに比べるとメモリリークの危険性が低くなっています。
使用頻度としてはunique_ptr > shared_ptr > weak_ptrを想定しているようです。
旧コメント:
些細な言葉の使い方の違いですが
null pointer というより dangling pointer と表現したほうがいい場所が、幾つかあると思います。
null pointer なら、生ポインタであっても if を使えば簡単に回避できますし。
2011-01-24 18:42 | SubaruG
Re: 些細な言葉の使い方の違いですが
そうですね、null pointerというよりはdangling pointerと表現すべきですね。直しておきました。
2011-01-24 18:52 | Naoki Rin