そろそろC++やります
そろそろC++をやります。そろそろC++をやりたいからです。
何回やるかはわかりません。基礎を理解するまではやろうと思います。
という感じでやっています。
※ 初心者がメモレベルで記録するので、技術記事としてはお力になれないかもしれません。
内容
weak_ptrの宣言
weak_ptr
は shared_ptrのリソースと同じクラステンプレートを持ちいて、shared_ptrから生成されます。
auto sp = make_shared<int>(145); weak_ptr<int> wp = sp;
weak_ptrとは
shared_ptrが持つリソースへの弱参照を保持するクラスです。
忘れていたのですが、unique_ptrもshared_ptrもweak_ptrも全てクラスなんですよね。
そして、weak_ptrはshared_ptrへの所有権を持つのでなく、そのリソースを覗き見、監視します。そのため、shared_ptrの参照カウントは増えません。
auto sp = make_shared<int>(145); cout << sp.use_count() << endl; weak_ptr<int> wp = sp; cout << sp.use_count() << endl;
Output
1 1
リソースの使用
リソースを使用する場合は、メンバー関数lock
を呼び出すことによって作成された、shared_ptr
オブジェクトを介して、使用することができます。
auto sp = make_shared<int>(145); weak_ptr<int> wp = sp; if (auto p = wp.lock()) { cout << *p << endl; }
Output
145
lock
関数で返されるshared_ptrは所有権を持ちます。
cout << sp.use_count() << endl; if (auto p = wp.lock()) { cout << sp.use_count() << endl; }
Output
1 2
なぜ、「lock」という命名なのかは、分かりませんでした。
if (auto p = wp.lock()) { cout << sp.use_count() << endl; cout << *sp << endl; auto sp2 = p; if (auto p = wp.lock()) { cout << sp.use_count() << endl; cout << *sp << endl; } }
以下のようなことは問題なくできました。
- lockの中で再度lock
- lockの中で元のshared_ptrの使用
- lockで得られたshared_ptrからshared_ptrの作成
get() みたいな名前でも良かったような気もしなくもないですが、lockでやって行きましょう。
循環参照 なぜweak_ptrが必要か
「weak_ptr使わないで、全てshared_ptrでやれば良い」という意見が出そうですが、循環参照に落ちいった時にweak_ptrが必要となります。
お互いをshare_ptr
型のメンバ変数として持つPairClass
を考えてみます。
class PairClass { public: PairClass(string _name) : name(_name) { } string name; shared_ptr<PairClass> pair; }; int main() { PairClass p1 = PairClass("pair1"); PairClass p2 = PairClass("pair2"); auto p1_sp = make_shared<PairClass>(p1); auto p2_sp = make_shared<PairClass>(p2); p2.pair = p1_sp; p1.pair = p2_sp; return 0; }
こちらのp2.pair = p1_sp; p1.pair = p2_sp;
の部分で、お互いに相手をshared_ptr
として保持しています。
本来であればスコープ{ }
を抜けた時に、p1
, p2
が解放され同時に変数であるshared_ptr
も解放されるはずです。しかし、p1
が解放されるタイミングでp1
のメンバ変数pair
は使用されているため、解放されません。同様な現象がp2
でも生じます。
よって、お互いに参照する循環参照が生じた時は適切にメモリが解放されないという現象が起きてしまいます。
これを対策するために、weak_ptr
を使用します。
参考リスト
感想
今回はweak_ptr
について触れて行きましたが、shared_ptr
の循環参照救済処置用のポインタだと分かり、使う場面も限定しそうです。
ポインタが一通り終わったので次回は一度、ポインタのまとめに入りたいと思います。