Your SlideShare is downloading. ×
0
shared_ptr & weak_ptr くらいおらいと http://twitter.com/Cryolite/
キーワードは 所有  ( ownership ) <ul><li>“…, so keeping track of an object’s  ownership  is hard work.”   –  More Effective C++ </...
所有とは… <ul><li>所有とは 権利 だ 俺が所有しているものを勝手に捨てるな </li></ul><ul><li>所有とは 義務 だ 1 回だけ,確実に,事後処理をしろ </li></ul>
所有を制するものが  C++  を制する <ul><li>所有の権利を主張しないと… 「俺がまだ使っているのに捨てられた!」 </li></ul><ul><li>=>  Dangling pointer </li></ul><ul><li>所有...
所有の種類と例 <ul><li>所有者がただ一人 ,  所有者変更不可 </li></ul><ul><ul><li>配列とその要素 </li></ul></ul><ul><ul><li>クラスオブジェクトとメンバ変数 </li></ul></u...
共有は難しい
共有は難しい 私が片付けましょう
共有は難しい 私が片付けましょう いえいえ,ここは 私が片付けましょう
共有は難しい 私が片付けましょう いえいえ,ここは 私が片付けましょう え,ちょ,俺まだ使ってる
shared_ptr –  共有を 所有カウント で簡単・安全に扱う 1 共有されるもの 所有カウント
shared_ptr –  共有を 所有カウント で簡単・安全に扱う 2 共有されるもの 所有カウント
shared_ptr –  共有を 所有カウント で簡単・安全に扱う 3 共有されるもの 所有カウント
shared_ptr –  共有を 所有カウント で簡単・安全に扱う 4 共有されるもの 所有カウント
shared_ptr –  共有を 所有カウント で簡単・安全に扱う 4 共有されるもの 所有カウント 所有カウントが 0 になったら 片づけを実行
所有カウントは所有の 権利を保障 する 1 共有されるもの 所有カウント 所有の権利: 誰かが所有していれば 勝手に片付けるな O.K.
所有カウントは所有の 義務を履行 する 0 共有されるもの 所有カウントが0になれば後片付け処理を実行 所有の義務: 1度だけ, 確実に, 片付け 所有カウント O.K.
shared_ptr –  共有を 所有カウント で簡単・安全に扱う 4 共有されるもの 所有カウント
shared_ptr –  共有を 所有カウント で簡単・安全に扱う 4 共有されるもの 所有カウント shared_ptr shared_ptr shared_ptr shared_ptr
shared_ptr  は所有 ( の義務と権利 ) とポインタだ <ul><li>ポインタとして動作する  shared_ptr C++  の生ポインタと同じように動作 </li></ul><ul><li>所有の権利を保障する  shared...
shared_ptr  の基本 <ul><li>{ </li></ul><ul><li>shared_ptr<int> p(new int(42)); </li></ul><ul><li>cout << *p << endl; </li></u...
shared_ptr  の基本 <ul><li>{ </li></ul><ul><li>shared_ptr<int> p(new int(42)); </li></ul><ul><li>cout << *p << endl; </li></u...
shared_ptr  の基本 <ul><li>{ </li></ul><ul><li>shared_ptr<int> p(new int(42)); </li></ul><ul><li>cout << *p << endl; </li></u...
shared_ptr – int  と同程度にスレッド安全 4 共有されるもの 所有カウント カウントの変化は 同期保護 shared_ptr shared_ptr shared_ptr shared_ptr
所有カウントは循環所有を扱えない 1 1 所有 所有 所有カウントが永遠に非 0
発表終わり
shared_ptr  の重要なデザインゴール <ul><li>ポインタと同等の型互換性 / バイナリ互換性 </li></ul><ul><li>非侵入性 – あなたのクラス定義に変更なし </li></ul>所有の共有・受け渡しを表現する 標...
オレオレスマートポインタ <ul><li>void processX(shared_ptr<X> px); </li></ul><ul><li>oreore_ptr<X> px(new X(…)); </li></ul><ul><li>proc...
オレオレスマートポインタ <ul><li>void processX(shared_ptr<X> px); </li></ul><ul><li>template<class P> struct D { </li></ul><ul><li>P p...
オレオレスマートポインタ <ul><li>void processX(shared_ptr<X> px); </li></ul><ul><li>template<class P> struct D { </li></ul><ul><li>P p...
所有しない <ul><li>void processX(shared_ptr<X> px); </li></ul><ul><li>static X x; //  静的変数 </li></ul><ul><li>struct NullDeleter...
所有しない <ul><li>void processX(shared_ptr<X> px); </li></ul><ul><li>static X x; //  静的変数 </li></ul><ul><li>Struct NullDeleter...
バイナリ境界を越える – 生ポインタの場合 int main(){ int *p = new int(42); f(p); p = 0; ..... } void f(int *p){ ..... ..... delete p; } a.exe...
バイナリ境界を越える –  shared_ptr  の場合 int main(){ shared_ptr<int> p(new int(42)); f(p); p.reset(); ..... } void f(shared_ptr<int> ...
バイナリ境界を越える –  shared_ptr  の場合 int main(){ shared_ptr<int> p(new int(42)); f(p); p.reset(); ..... } void f(shared_ptr<int> ...
バイナリ境界を越える –  shared_ptr  の場合 int main(){ shared_ptr<int> p(new int(42)); f(p); p.reset(); ..... } void f(shared_ptr<int> ...
バイナリ境界を越える –  shared_ptr  の場合 int main(){ shared_ptr<int> p(new int(42)); f(p); p.reset(); ..... } void f(shared_ptr<int> ...
所有だけの  shared_ptr shared_ptr<int> p(new int(42)); //  (A) shared_ptr<void> q = p; p.reset(); //  以下,  (A)   で生成した  int  は ...
shared_ptr<void>  による遅延解放 <ul><li>// HeavyToDispose  は削除のコスト大 </li></ul><ul><li>shared_ptr<HeavyToDispose> px(…); </li></u...
shared_ptr<void>  による遅延解放 <ul><li>vector<shared_ptr<void> > to_be_disposed; </li></ul><ul><li>shared_ptr<HeavyToDispose1> ...
weak_ptr 4,  2 共有されるもの 所有カウント shared_ptr shared_ptr shared_ptr shared_ptr weak_ptr weak_ptr 弱いカウント
weak_ptr 0,  2 共有されるもの 所有カウント shared_ptr shared_ptr shared_ptr shared_ptr weak_ptr weak_ptr 弱いカウント
weak_ptr 0,  2 共有されるもの 所有カウント weak_ptr weak_ptr 弱いカウント 所有カウントが 0 になったら 片づけを実行
weak_ptr 0,  2 所有カウント weak_ptr weak_ptr 弱いカウント
weak_ptr 0,  0 所有カウント weak_ptr weak_ptr 弱いカウント
weak_ptr 0,   0 weak_ptr weak_ptr 弱いカウントが 0 になったら カウントオブジェクトを片付け
weak_ptr  にできること – その 1 4,  2 共有されるもの 所有カウント shared_ptr shared_ptr shared_ptr shared_ptr weak_ptr weak_ptr 弱いカウント 「所有カウントが...
weak_ptr  にできること – その 1 0,  2 所有カウント weak_ptr weak_ptr 弱いカウント 「所有カウントが 0 かどうか?」に答える weak_ptr::expired ==  true
weak_ptr  にできること – その 1 0,  2 所有カウント weak_ptr weak_ptr 弱いカウント 「所有カウントが 0 かどうか?」に答える = 「対象が死んでいるかどうか?」に答える
weak_ptr  にできること – その 2 1,  2 共有されるもの 所有カウント shared_ptr weak_ptr weak_ptr 弱いカウント 対象が生きていたら,それを 所有する  shared_ptr  を作り出せる
weak_ptr  にできること – その 2 2,  2 共有されるもの 所有カウント shared_ptr weak_ptr weak_ptr 弱いカウント shared_ptr 対象が生きていたら,それを 所有する  shared_ptr...
weak_ptr  にできること – その 2 0,  2 所有カウント weak_ptr weak_ptr 弱いカウント 対象が死んでいたら空の  shared_ptr  しか取り出せない
weak_ptr  にできること – その 2 0,  2 所有カウント weak_ptr weak_ptr 弱いカウント shared_ptr 対象が死んでいたら空の  shared_ptr  しか取り出せない
weak_ptr  にできることのまとめ <ul><li>「対象が生きているかどうか?」を答える プロクシ </li></ul><ul><li>対象が生きていたら  shared_ptr  に 格上げ可能 </li></ul>
weak_ptr  の基本 <ul><li>shared_ptr<int> p(new int(42)); //  (A) </li></ul><ul><li>weak_ptr<int> wp = p; </li></ul><ul><li>co...
生ポインタから  shared_ptr  を取得したい <ul><li>void Framework::onEvent(X *p) </li></ul><ul><li>{ </li></ul><ul><li>// *p  を所有する  shar...
this  への  shared_ptr <ul><li>struct X { </li></ul><ul><li>shared_ptr<X> this_; // this  への  shared_ptr </li></ul><ul><li>s...
this  への  shared_ptr  はダメ <ul><li>struct X { </li></ul><ul><li>shared_ptr<X> this_; // this  への  shared_ptr </li></ul><ul>...
this  への  shared_ptr  はダメ <ul><li>struct X { </li></ul><ul><li>shared_ptr<X> this_; // this  への  shared_ptr </li></ul><ul>...
weak_ptr  の使い方 –  this  への  weak_ptr <ul><li>struct X { </li></ul><ul><li>weak_ptr<X> this_; // this  への  weak_ptr </li></...
weak_ptr  の使い方 –  this  への  weak_ptr <ul><li>struct X { </li></ul><ul><li>weak_ptr<X> this_; // this  への  weak_ptr </li></...
Observer (Publisher/Subscriber)
Observer でよくある事故
Observer でよくある事故 死んだオブジェクトにアクセス
安全な Observer <ul><li>死んだオブジェクトにイベントを通知しない </li></ul><ul><li>イベント通知中に  subscriber  を解放させない </li></ul>
安全な Observer void Publisher::subscribe(function<void ()> call_back, weak_ptr<void> wp); shared_ptr<Subscriber1> p… Publish...
安全な Observer weak_ptr<void> wp…; // subscriber  への  weak_ptr if (shared_ptr<void> p = wp.lock()) { //  生きているときだけ通知  + call...
安全な Observer … ということが  Boost.Signal2  で出来ます 鍵は  weak_ptr<void> & shared_ptr<void>
オブジェクト間グローバルマッピング a b c share_ptr share_ptr share_ptr share_ptr
オブジェクト間グローバルマッピング a b c map<void *, Y> g_map; //  グローバル y1 y2 y3 share_ptr share_ptr share_ptr share_ptr
オブジェクト間グローバルマッピング a b c y1 y2 y3 share_ptr share_ptr share_ptr share_ptr c  が消えると… map<void *, Y> g_map; //  グローバル
オブジェクト間グローバルマッピング a b c y1 y2 y3 share_ptr share_ptr share_ptr share_ptr c  が消えると… 無駄なマップエントリ ( デッドマップ )  が発生 map<void *, ...
策 1.  キーを  weak_ptr  にして適度にクリーンアップ a b c map< weak_ptr<void> , Y> g_map; y1 y2 y3 share_ptr share_ptr
策 1.  キーを  weak_ptr  にして適度にクリーンアップ a b c map< weak_ptr<void> , Y> g_map; y1 y2 y3 share_ptr share_ptr //  以下を適度に実行 for ( a...
策 1.  キーを  weak_ptr  にして適度にクリーンアップ a b c map< weak_ptr<void> , Y> g_map; y1 y2 y3 share_ptr share_ptr デッドマップが適度に解消される
策2. マップエントリも所有する a b c y1 y2 y3 share_ptr share_ptr share_ptr share_ptr map<void *, Y>
策2. マップエントリも所有する a b c y1 y2 y3 share_ptr share_ptr share_ptr share_ptr map<void *, Y> struct D{ map<void *, Y> &m_; void ...
策2. マップエントリも所有する a b c map<void *, Y> y1 y2 y3 share_ptr share_ptr share_ptr share_ptr c  を所有する  shared_ptr  がなくなると…
策2. マップエントリも所有する a b c map<void *, Y> y1 y2 y3 share_ptr share_ptr share_ptr share_ptr c  を所有する  shared_ptr  がなくなると… c  をキ...
循環所有を何とかする <ul><li>//  こういうことがしたい </li></ul><ul><li>shared_ptr<X> px = …; </li></ul><ul><li>shared_ptr<Y> py = …; </li></u...
循環所有を何とかする <ul><li>//  こういうことがしたい </li></ul><ul><li>shared_ptr<X> px = …; </li></ul><ul><li>shared_ptr<Y> py = …; </li></u...
循環所有を何とかする <ul><li>//  こういうことがしたい </li></ul><ul><li>shared_ptr<X> px = …; </li></ul><ul><li>shared_ptr<Y> py = …; </li></u...
循環所有を何とかする <ul><li>//  こういうことがしたい </li></ul><ul><li>shared_ptr<X> px = …; </li></ul><ul><li>shared_ptr<Y> py = …; </li></u...
循環所有を何とかする <ul><li>//  こういうことがしたい </li></ul><ul><li>shared_ptr<X> px = …; </li></ul><ul><li>shared_ptr<Y> py = …; </li></u...
まとめ <ul><li>C++  では所有が重要 </li></ul><ul><li>shared_ptr  は所有者が複数居る場合に </li></ul><ul><ul><li>所有カウントで簡単・安全に動作 </li></ul></ul><...
Upcoming SlideShare
Loading in...5
×

shared_ptr & weak_ptr (ppt 第2版, DL 専用)

1,357

Published on

Web 上ではフォントが崩れます. (DL 専用)
Web 上で見る方は http://bit.ly/7dyNmz をどうぞ.
2009/12/12 Boost.勉強会 プレゼン資料 ppt 第2版.
初版の明らかな不手際を最低限だけ修正.
プレゼン発表の録画は http://bit.ly/6yjSkz です.

Published in: Technology
0 Comments
1 Like
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total Views
1,357
On Slideshare
0
From Embeds
0
Number of Embeds
0
Actions
Shares
0
Downloads
26
Comments
0
Likes
1
Embeds 0
No embeds

No notes for slide

Transcript of "shared_ptr & weak_ptr (ppt 第2版, DL 専用)"

  1. 1. shared_ptr & weak_ptr くらいおらいと http://twitter.com/Cryolite/
  2. 2. キーワードは 所有 ( ownership ) <ul><li>“…, so keeping track of an object’s ownership is hard work.” – More Effective C++ </li></ul><ul><li>“Observe the canonical exception-safety rules: Always use the “RAII” idiom to resource ownership and management.” – Exceptional C++ </li></ul><ul><li>“Containers of raw pointers make manual ownership management tricky, so …” – Modern C++ Design </li></ul>
  3. 3. 所有とは… <ul><li>所有とは 権利 だ 俺が所有しているものを勝手に捨てるな </li></ul><ul><li>所有とは 義務 だ 1 回だけ,確実に,事後処理をしろ </li></ul>
  4. 4. 所有を制するものが C++ を制する <ul><li>所有の権利を主張しないと… 「俺がまだ使っているのに捨てられた!」 </li></ul><ul><li>=> Dangling pointer </li></ul><ul><li>所有の義務を果たしていないと… 「誰も使ってないのに片付いていない!」 </li></ul><ul><li>=> Memory leak </li></ul>
  5. 5. 所有の種類と例 <ul><li>所有者がただ一人 , 所有者変更不可 </li></ul><ul><ul><li>配列とその要素 </li></ul></ul><ul><ul><li>クラスオブジェクトとメンバ変数 </li></ul></ul><ul><ul><li>関数スコープ ( の実行 ) と自動変数 </li></ul></ul><ul><ul><li>プログラム ( の実行 ) と静的変数 </li></ul></ul><ul><li>所有者がただ一人 , 所有者変更可 </li></ul><ul><ul><li>std::auto_ptr </li></ul></ul><ul><ul><li>( ムーブセマンティクス ) </li></ul></ul><ul><li>共有 – 所有者が複数 </li></ul><ul><ul><li>boost::shared_ptr </li></ul></ul>
  6. 6. 共有は難しい
  7. 7. 共有は難しい 私が片付けましょう
  8. 8. 共有は難しい 私が片付けましょう いえいえ,ここは 私が片付けましょう
  9. 9. 共有は難しい 私が片付けましょう いえいえ,ここは 私が片付けましょう え,ちょ,俺まだ使ってる
  10. 10. shared_ptr – 共有を 所有カウント で簡単・安全に扱う 1 共有されるもの 所有カウント
  11. 11. shared_ptr – 共有を 所有カウント で簡単・安全に扱う 2 共有されるもの 所有カウント
  12. 12. shared_ptr – 共有を 所有カウント で簡単・安全に扱う 3 共有されるもの 所有カウント
  13. 13. shared_ptr – 共有を 所有カウント で簡単・安全に扱う 4 共有されるもの 所有カウント
  14. 14. shared_ptr – 共有を 所有カウント で簡単・安全に扱う 4 共有されるもの 所有カウント 所有カウントが 0 になったら 片づけを実行
  15. 15. 所有カウントは所有の 権利を保障 する 1 共有されるもの 所有カウント 所有の権利: 誰かが所有していれば 勝手に片付けるな O.K.
  16. 16. 所有カウントは所有の 義務を履行 する 0 共有されるもの 所有カウントが0になれば後片付け処理を実行 所有の義務: 1度だけ, 確実に, 片付け 所有カウント O.K.
  17. 17. shared_ptr – 共有を 所有カウント で簡単・安全に扱う 4 共有されるもの 所有カウント
  18. 18. shared_ptr – 共有を 所有カウント で簡単・安全に扱う 4 共有されるもの 所有カウント shared_ptr shared_ptr shared_ptr shared_ptr
  19. 19. shared_ptr は所有 ( の義務と権利 ) とポインタだ <ul><li>ポインタとして動作する shared_ptr C++ の生ポインタと同じように動作 </li></ul><ul><li>所有の権利を保障する shared_ptr ポインタとして指しているものは生きている </li></ul><ul><li>所有の義務を履行する shared_ptr 所有カウントが 0 になったら関数オブジェクト ( デリータ ) を実行 </li></ul>強いポインタ 所有しているものとポインタが 指しているものを一致させる delete だけじゃない
  20. 20. shared_ptr の基本 <ul><li>{ </li></ul><ul><li>shared_ptr<int> p(new int(42)); </li></ul><ul><li>cout << *p << endl; </li></ul><ul><li>shared_ptr<int> q = p; </li></ul><ul><li>p.reset(); </li></ul><ul><li>cout << *q << endl; </li></ul><ul><li>} </li></ul>
  21. 21. shared_ptr の基本 <ul><li>{ </li></ul><ul><li>shared_ptr<int> p(new int(42)); </li></ul><ul><li>cout << *p << endl; </li></ul><ul><li>shared_ptr<int> q = p; </li></ul><ul><li>p.reset(); </li></ul><ul><li>cout << *q << endl; </li></ul><ul><li>} </li></ul>ポインタとして動作 + 権利を保障 ( 参照外しが安全 )
  22. 22. shared_ptr の基本 <ul><li>{ </li></ul><ul><li>shared_ptr<int> p(new int(42)); </li></ul><ul><li>cout << *p << endl; </li></ul><ul><li>shared_ptr<int> q = p; </li></ul><ul><li>p.reset(); </li></ul><ul><li>cout << *q << endl; </li></ul><ul><li>} </li></ul>ポインタとして動作 + 権利を保障 ( 参照外しが安全 ) 義務を履行
  23. 23. shared_ptr – int と同程度にスレッド安全 4 共有されるもの 所有カウント カウントの変化は 同期保護 shared_ptr shared_ptr shared_ptr shared_ptr
  24. 24. 所有カウントは循環所有を扱えない 1 1 所有 所有 所有カウントが永遠に非 0
  25. 25. 発表終わり
  26. 26. shared_ptr の重要なデザインゴール <ul><li>ポインタと同等の型互換性 / バイナリ互換性 </li></ul><ul><li>非侵入性 – あなたのクラス定義に変更なし </li></ul>所有の共有・受け渡しを表現する 標準インタフェイスの確立
  27. 27. オレオレスマートポインタ <ul><li>void processX(shared_ptr<X> px); </li></ul><ul><li>oreore_ptr<X> px(new X(…)); </li></ul><ul><li>processX(px); // コンパイルエラー </li></ul>
  28. 28. オレオレスマートポインタ <ul><li>void processX(shared_ptr<X> px); </li></ul><ul><li>template<class P> struct D { </li></ul><ul><li>P p_; </li></ul><ul><li>void operator()(void const *) { p_.reset(); } </li></ul><ul><li>}; </li></ul><ul><li>oreore_ptr<X> px(new X(…)); </li></ul><ul><li>shared_ptr<X> qx(px.get(), D<oreore_ptr<X> >(px)); </li></ul><ul><li>processX(qx); // O.K. </li></ul>
  29. 29. オレオレスマートポインタ <ul><li>void processX(shared_ptr<X> px); </li></ul><ul><li>template<class P> struct D { </li></ul><ul><li>P p_; </li></ul><ul><li>void operator()(void const *) { p_.reset(); } </li></ul><ul><li>}; </li></ul><ul><li>oreore_ptr<X> px(new X(…)); </li></ul><ul><li>shared_ptr<X> qx(px.get(), D<oreore_ptr<X> >(px)); </li></ul><ul><li>processX(qx); </li></ul>「所有」は型に現れない = コンストラクタで「所有」が決まる shared_ptr の 「所有」は型に現れない ポイント 2 ポイント 1
  30. 30. 所有しない <ul><li>void processX(shared_ptr<X> px); </li></ul><ul><li>static X x; // 静的変数 </li></ul><ul><li>struct NullDeleter { </li></ul><ul><li>void operator()(void *){} </li></ul><ul><li>}; </li></ul><ul><li>shared_ptr<X> px(&x, NullDeleter()); </li></ul><ul><li>processX(px); </li></ul>
  31. 31. 所有しない <ul><li>void processX(shared_ptr<X> px); </li></ul><ul><li>static X x; // 静的変数 </li></ul><ul><li>Struct NullDeleter { </li></ul><ul><li>void operator()(void *){} </li></ul><ul><li>}; </li></ul><ul><li>shared_ptr<X> px(&x, NullDeleter()); </li></ul><ul><li>processX(px); </li></ul>shared_ptr の 「所有」は型に現れない ポイント 1 「所有」は型に現れない = コンストラクタで「所有」が決まる ポイント 2
  32. 32. バイナリ境界を越える – 生ポインタの場合 int main(){ int *p = new int(42); f(p); p = 0; ..... } void f(int *p){ ..... ..... delete p; } a.exe ( デバッグビルド ) b.dll ( リリースビルド ) 異なるコンパイル設定の new と delete の 組み合わせは環境によっては ダウト
  33. 33. バイナリ境界を越える – shared_ptr の場合 int main(){ shared_ptr<int> p(new int(42)); f(p); p.reset(); ..... } void f(shared_ptr<int> p){ ..... ..... p.reset(); } a.exe ( デバッグビルド ) b.dll ( リリースビルド )
  34. 34. バイナリ境界を越える – shared_ptr の場合 int main(){ shared_ptr<int> p(new int(42)); f(p); p.reset(); ..... } void f(shared_ptr<int> p){ ..... ..... p.reset(); } a.exe ( デバッグビルド ) b.dll ( リリースビルド ) デバッグビルドの delete をここで設定
  35. 35. バイナリ境界を越える – shared_ptr の場合 int main(){ shared_ptr<int> p(new int(42)); f(p); p.reset(); ..... } void f(shared_ptr<int> p){ ..... ..... p.reset(); } a.exe ( デバッグビルド ) b.dll ( リリースビルド ) デバッグビルドの delete をここで設定 デバッグビルドの delete が呼び出される
  36. 36. バイナリ境界を越える – shared_ptr の場合 int main(){ shared_ptr<int> p(new int(42)); f(p); p.reset(); ..... } void f(shared_ptr<int> p){ ..... ..... p.reset(); } a.exe ( デバッグビルド ) b.dll ( リリースビルド ) デバッグビルドの delete が呼び出される デバッグビルドの delete をここで設定 どの delete が設定されていようが バイナリ互換性を維持
  37. 37. 所有だけの shared_ptr shared_ptr<int> p(new int(42)); // (A) shared_ptr<void> q = p; p.reset(); // 以下, (A) で生成した int は q が所有
  38. 38. shared_ptr<void> による遅延解放 <ul><li>// HeavyToDispose は削除のコスト大 </li></ul><ul><li>shared_ptr<HeavyToDispose> px(…); </li></ul><ul><li>… </li></ul><ul><li>// ここで削除して処理が止まると困る… </li></ul><ul><li>px.reset(); </li></ul>
  39. 39. shared_ptr<void> による遅延解放 <ul><li>vector<shared_ptr<void> > to_be_disposed; </li></ul><ul><li>shared_ptr<HeavyToDispose1> px(…); </li></ul><ul><li>shared_ptr<HeavyToDispose2> py(…); </li></ul><ul><li>… </li></ul><ul><li>// ここで削除して処理が止まると困る… </li></ul><ul><li>to_be_disposed.push_back(px); px.reset(); </li></ul><ul><li>to_be_disposed.push_back(py); py.reset(); </li></ul><ul><li>… </li></ul><ul><li>// 適当なタイミング or 別スレッドで </li></ul><ul><li>// to_be_disposed.clear() を実行 </li></ul>
  40. 40. weak_ptr 4, 2 共有されるもの 所有カウント shared_ptr shared_ptr shared_ptr shared_ptr weak_ptr weak_ptr 弱いカウント
  41. 41. weak_ptr 0, 2 共有されるもの 所有カウント shared_ptr shared_ptr shared_ptr shared_ptr weak_ptr weak_ptr 弱いカウント
  42. 42. weak_ptr 0, 2 共有されるもの 所有カウント weak_ptr weak_ptr 弱いカウント 所有カウントが 0 になったら 片づけを実行
  43. 43. weak_ptr 0, 2 所有カウント weak_ptr weak_ptr 弱いカウント
  44. 44. weak_ptr 0, 0 所有カウント weak_ptr weak_ptr 弱いカウント
  45. 45. weak_ptr 0, 0 weak_ptr weak_ptr 弱いカウントが 0 になったら カウントオブジェクトを片付け
  46. 46. weak_ptr にできること – その 1 4, 2 共有されるもの 所有カウント shared_ptr shared_ptr shared_ptr shared_ptr weak_ptr weak_ptr 弱いカウント 「所有カウントが 0 かどうか?」に答える weak_ptr::expired == false
  47. 47. weak_ptr にできること – その 1 0, 2 所有カウント weak_ptr weak_ptr 弱いカウント 「所有カウントが 0 かどうか?」に答える weak_ptr::expired == true
  48. 48. weak_ptr にできること – その 1 0, 2 所有カウント weak_ptr weak_ptr 弱いカウント 「所有カウントが 0 かどうか?」に答える = 「対象が死んでいるかどうか?」に答える
  49. 49. weak_ptr にできること – その 2 1, 2 共有されるもの 所有カウント shared_ptr weak_ptr weak_ptr 弱いカウント 対象が生きていたら,それを 所有する shared_ptr を作り出せる
  50. 50. weak_ptr にできること – その 2 2, 2 共有されるもの 所有カウント shared_ptr weak_ptr weak_ptr 弱いカウント shared_ptr 対象が生きていたら,それを 所有する shared_ptr を作り出せる
  51. 51. weak_ptr にできること – その 2 0, 2 所有カウント weak_ptr weak_ptr 弱いカウント 対象が死んでいたら空の shared_ptr しか取り出せない
  52. 52. weak_ptr にできること – その 2 0, 2 所有カウント weak_ptr weak_ptr 弱いカウント shared_ptr 対象が死んでいたら空の shared_ptr しか取り出せない
  53. 53. weak_ptr にできることのまとめ <ul><li>「対象が生きているかどうか?」を答える プロクシ </li></ul><ul><li>対象が生きていたら shared_ptr に 格上げ可能 </li></ul>
  54. 54. weak_ptr の基本 <ul><li>shared_ptr<int> p(new int(42)); // (A) </li></ul><ul><li>weak_ptr<int> wp = p; </li></ul><ul><li>cout << wp.expired() << endl; // => “false” </li></ul><ul><li>shared_ptr<int> q = wp.lock(); </li></ul><ul><li>cout << *q << endl; // => “42”, q も所有 </li></ul><ul><li>p.reset(); q.reset(); // (A) の int を解放 </li></ul><ul><li>cout << wp.expired() << endl; // => “true” </li></ul><ul><li>shared_ptr<int> r = wp.lock(); </li></ul><ul><li>assert(r == 0); </li></ul>
  55. 55. 生ポインタから shared_ptr を取得したい <ul><li>void Framework::onEvent(X *p) </li></ul><ul><li>{ </li></ul><ul><li>// *p を所有する shared_ptr を取りたい </li></ul><ul><li>} </li></ul>
  56. 56. this への shared_ptr <ul><li>struct X { </li></ul><ul><li>shared_ptr<X> this_; // this への shared_ptr </li></ul><ul><li>shared_ptr<X> getShared(){ return this_; } </li></ul><ul><li>}; </li></ul><ul><li>void Framework::onEvent(X *p) </li></ul><ul><li>{ </li></ul><ul><li>shared_ptr<X> px = p->getShared(); </li></ul><ul><li>} </li></ul>
  57. 57. this への shared_ptr はダメ <ul><li>struct X { </li></ul><ul><li>shared_ptr<X> this_; // this への shared_ptr </li></ul><ul><li>shared_ptr<X> getShared(){ return this_; } </li></ul><ul><li>}; </li></ul><ul><li>void Framework::onEvent(X *p) </li></ul><ul><li>{ </li></ul><ul><li>shared_ptr<X> px = p->getShared(); </li></ul><ul><li>} </li></ul>
  58. 58. this への shared_ptr はダメ <ul><li>struct X { </li></ul><ul><li>shared_ptr<X> this_; // this への shared_ptr </li></ul><ul><li>shared_ptr<X> getShared(){ return this_; } </li></ul><ul><li>}; </li></ul><ul><li>void Framework::onEvent(X *p) </li></ul><ul><li>{ </li></ul><ul><li>shared_ptr<X> px = p->getShared(); </li></ul><ul><li>} </li></ul>X X::shared_ptr this_ クラスオブジェクトは メンバ変数を所有 所有 Q. なぜダメか? A. 所有が循環しているのでダメ
  59. 59. weak_ptr の使い方 – this への weak_ptr <ul><li>struct X { </li></ul><ul><li>weak_ptr<X> this_; // this への weak_ptr </li></ul><ul><li>shared_ptr<X> getShared(){ return this_; } </li></ul><ul><li>}; </li></ul><ul><li>void Framework::onEvent(X *p) </li></ul><ul><li>{ </li></ul><ul><li>shared_ptr<X> px = p->getShared(); </li></ul><ul><li>} </li></ul>
  60. 60. weak_ptr の使い方 – this への weak_ptr <ul><li>struct X { </li></ul><ul><li>weak_ptr<X> this_; // this への weak_ptr </li></ul><ul><li>shared_ptr<X> getShared(){ return this_; } </li></ul><ul><li>}; </li></ul><ul><li>void Framework::onEvent(X *p) </li></ul><ul><li>{ </li></ul><ul><li>shared_ptr<X> px = p->getShared(); </li></ul><ul><li>} </li></ul>参考: boost::enable_shared_from_this
  61. 61. Observer (Publisher/Subscriber)
  62. 62. Observer でよくある事故
  63. 63. Observer でよくある事故 死んだオブジェクトにアクセス
  64. 64. 安全な Observer <ul><li>死んだオブジェクトにイベントを通知しない </li></ul><ul><li>イベント通知中に subscriber を解放させない </li></ul>
  65. 65. 安全な Observer void Publisher::subscribe(function<void ()> call_back, weak_ptr<void> wp); shared_ptr<Subscriber1> p… Publisher::subscribe( bind(&Subscriber1::notifyEvent, p.get()), p);
  66. 66. 安全な Observer weak_ptr<void> wp…; // subscriber への weak_ptr if (shared_ptr<void> p = wp.lock()) { // 生きているときだけ通知 + call_back 中だけ所有 call_back(); }
  67. 67. 安全な Observer … ということが Boost.Signal2 で出来ます 鍵は weak_ptr<void> & shared_ptr<void>
  68. 68. オブジェクト間グローバルマッピング a b c share_ptr share_ptr share_ptr share_ptr
  69. 69. オブジェクト間グローバルマッピング a b c map<void *, Y> g_map; // グローバル y1 y2 y3 share_ptr share_ptr share_ptr share_ptr
  70. 70. オブジェクト間グローバルマッピング a b c y1 y2 y3 share_ptr share_ptr share_ptr share_ptr c が消えると… map<void *, Y> g_map; // グローバル
  71. 71. オブジェクト間グローバルマッピング a b c y1 y2 y3 share_ptr share_ptr share_ptr share_ptr c が消えると… 無駄なマップエントリ ( デッドマップ ) が発生 map<void *, Y> g_map; // グローバル
  72. 72. 策 1. キーを weak_ptr にして適度にクリーンアップ a b c map< weak_ptr<void> , Y> g_map; y1 y2 y3 share_ptr share_ptr
  73. 73. 策 1. キーを weak_ptr にして適度にクリーンアップ a b c map< weak_ptr<void> , Y> g_map; y1 y2 y3 share_ptr share_ptr // 以下を適度に実行 for ( auto i = g_map.begin(); i != g_map.end();) { if (i->first.expired()) g_map.erase(i++); else ++i; }
  74. 74. 策 1. キーを weak_ptr にして適度にクリーンアップ a b c map< weak_ptr<void> , Y> g_map; y1 y2 y3 share_ptr share_ptr デッドマップが適度に解消される
  75. 75. 策2. マップエントリも所有する a b c y1 y2 y3 share_ptr share_ptr share_ptr share_ptr map<void *, Y>
  76. 76. 策2. マップエントリも所有する a b c y1 y2 y3 share_ptr share_ptr share_ptr share_ptr map<void *, Y> struct D{ map<void *, Y> &m_; void operator()(void *p){ m_.erase(p) ; delete p; } }; D d(g_map); shared_ptr<C> pc(new C(), D(g_map)); g_map.insert(make_pair(pc.get(), Y(…)));
  77. 77. 策2. マップエントリも所有する a b c map<void *, Y> y1 y2 y3 share_ptr share_ptr share_ptr share_ptr c を所有する shared_ptr がなくなると…
  78. 78. 策2. マップエントリも所有する a b c map<void *, Y> y1 y2 y3 share_ptr share_ptr share_ptr share_ptr c を所有する shared_ptr がなくなると… c をキーとするエントリも自動で erase
  79. 79. 循環所有を何とかする <ul><li>// こういうことがしたい </li></ul><ul><li>shared_ptr<X> px = …; </li></ul><ul><li>shared_ptr<Y> py = …; </li></ul><ul><li>pyy = px->getSharedY(); // X が Y を所有? </li></ul><ul><li>assert(pyy == py); </li></ul><ul><li>pxx = py->getSharedX(); // Y が X を所有? </li></ul><ul><li>assert(pxx == px); </li></ul>
  80. 80. 循環所有を何とかする <ul><li>// こういうことがしたい </li></ul><ul><li>shared_ptr<X> px = …; </li></ul><ul><li>shared_ptr<Y> py = …; </li></ul><ul><li>pyy = px->getSharedY(); // X が Y を所有? </li></ul><ul><li>assert(pyy == py); </li></ul><ul><li>pxx = py->getSharedX(); // Y が X を所有? </li></ul><ul><li>assert(pxx == px); </li></ul>X Y 所有 所有 ?
  81. 81. 循環所有を何とかする <ul><li>// こういうことがしたい </li></ul><ul><li>shared_ptr<X> px = …; </li></ul><ul><li>shared_ptr<Y> py = …; </li></ul><ul><li>pyy = px->getSharedY(); // X が Y を所有? </li></ul><ul><li>assert(pyy == py); </li></ul><ul><li>pxx = py->getSharedX(); // Y が X を所有? </li></ul><ul><li>assert(pxx == px); </li></ul>X Y shared_ptr 所有 所有
  82. 82. 循環所有を何とかする <ul><li>// こういうことがしたい </li></ul><ul><li>shared_ptr<X> px = …; </li></ul><ul><li>shared_ptr<Y> py = …; </li></ul><ul><li>pyy = px->getSharedY(); // X が Y を所有? </li></ul><ul><li>assert(pyy == py); </li></ul><ul><li>pxx = py->getSharedX(); // Y が X を所有? </li></ul><ul><li>assert(pxx == px); </li></ul>X Y shared_ptr 所有 所有 ポイント shared_ptr<X>
  83. 83. 循環所有を何とかする <ul><li>// こういうことがしたい </li></ul><ul><li>shared_ptr<X> px = …; </li></ul><ul><li>shared_ptr<Y> py = …; </li></ul><ul><li>pyy = px->getSharedY(); // X が Y を所有? </li></ul><ul><li>assert(pyy == py); </li></ul><ul><li>pxx = py->getSharedX(); // Y が X を所有? </li></ul><ul><li>assert(pxx == px); </li></ul>X Y shared_ptr 所有 所有 shared_ptr<Y> ポイント
  84. 84. まとめ <ul><li>C++ では所有が重要 </li></ul><ul><li>shared_ptr は所有者が複数居る場合に </li></ul><ul><ul><li>所有カウントで簡単・安全に動作 </li></ul></ul><ul><ul><li>動的デリータによる高い互換性を維持 </li></ul></ul><ul><li>weak_ptr </li></ul><ul><ul><li>「生きているかどうか」を答えるプロキシ </li></ul></ul><ul><ul><li>shared_ptr に格上げして一時的に所有 </li></ul></ul><ul><li>shared_ptr / weak_ptr で楽しい C++ ライフ </li></ul>
  1. A particular slide catching your eye?

    Clipping is a handy way to collect important slides you want to go back to later.

×