SlideShare a Scribd company logo
1 of 27
Download to read offline
勉強会資料:スマートポインタ入門 
@NU-Pan 
2014/07/10(木) 
@NU-Pan 勉強会資料:スマートポインタ入門2014/07/10(木) 1 / 27
生ポインタは便利 
ポインタの偉大な点 
他の変数を指し示せる変数である 
演算できる 
無効値であるNULL が存在する 
非常に低コスト(実体は64bit or 32bit の符号なし整数ですから!) 
例えば:線形探索 
1 // 線形探索関数 
2 template < typename T> 
3 T* Search (T* begin , T* end , T value ){ 
4 for(T* i= begin ; i!= end ; ++i){ 
5 if (*i== value ){ 
6 return i; 
7 } 
8 } 
9 return NULL ; 
10 } 
11 
12 // こう使う 
13 double Array [10] = {...}; 
14 double * Result = Search (Array , Array +10 , 810); 
@NU-Pan 勉強会資料:スマートポインタ入門2014/07/10(木) 2 / 27
生ポインタは危ない 
1 // 画像を作る関数 
2 uint8_t * CreateImage (int w, int h, int c){ 
3 uint8_t * Image = new uint8_t [w*h*c]; 
4 
5 uint8_t * Pixel = Image ; 
6 for(int i =0; i<w*h*c; ++i){ // <- バッファオーバーラン! 
7 memset (Pixel , 127 , c); 
8 Pixel += c; 
9 } 
10 
11 return Image ; 
12 } 
13 
14 // 画像に何かの処理をする 
15 void SomeProcess ( uint8_t * image , int w, int h, int c){ 
16 uint8_t * Buffer = CreateImage (w, h, c); 
17 
18 // 何かの処理をいっぱい書く 
19 
20 }// <- メモリリーク! 
確かに便利だが危険も伴う 
できればこういうリスクは抱えたくない 
@NU-Pan 勉強会資料:スマートポインタ入門2014/07/10(木) 3 / 27
生ポインタの扱い方 
基本的な方針 
速度が大事なところではオーバーヘッドの少ない生ポインタ 
速度よりも楽ができること" が大事なところではより安全な別の手段を 
使う 
実行速度と安全性のトレードオフを考えて使いましょうということ 
例えば:引数をconst 参照で置き換え 
1 // コピー出来ないクラス 
2 class FileWriter { 
3 private : 
4 FileWriter ( const FileWriter &); 
5 SomeClass & operator =( const FileWriter &); 
6 public : 
7 // いろいろ 
8 }; 
9 
10 // ポインタでもとれるが参照の方が安全 
11 void SomeProcess ( FileWriter & writer , ...){ 
12 // なにか処理する 
13 } 
@NU-Pan 勉強会資料:スマートポインタ入門2014/07/10(木) 4 / 27
生ポインタの扱い方 
例えば:関数の戻り値をboost.optional にする 
1 // 答えが出ないかも知れない小難しい計算をする 
2 boost :: optional <int > SomeProcess (...){ 
3 . 
4 . 
5 . 
6 // 途中で計算が破綻した! 
7 if (...){ 
8 return boost :: optional <int >(); // 明確な無効値を返却 
9 } 
10 . 
11 . 
12 . 
13 } 
14 
15 // こう使う 
16 boost :: optional <int > Result = SomeProcess (...); 
17 if( Result ){ // そのまま真理値として有効/ 無効を判別できる 
18 int value = * Result ; // 値は* でとれる 
19 } else { 
20 // 失敗したのでエラー処理 
21 } 
@NU-Pan 勉強会資料:スマートポインタ入門2014/07/10(木) 5 / 27
生ポインタの扱い方 
例えば:ポインタをクラスで包んでリソース管理? 
・ 
・ 
・ 
・ 
・ 
・ 
管理"って簡単に言うけど具体的に何するんですか? 
@NU-Pan 勉強会資料:スマートポインタ入門2014/07/10(木) 6 / 27
リソース管理クラスis 何 
管理" に何を求めているのか? 
自分で確保したリソースの後始末をいい感じに" やってほしい 
いい感じ" とは適切なタイミング" でリソースを解放してくれること 
適切なタイミング" とは大抵の場合はリソースが不要になったタイミング 
リソース管理クラスとはつまり 
生のポインタを格納 
ポインタの示すリソースが不要になったら自動で解放してくれる 
そんな機能を持ったクラスのこと 
そういうクラスのことをスマートポインタという 
@NU-Pan 勉強会資料:スマートポインタ入門2014/07/10(木) 7 / 27
スマートポインタ 
スマートポインタの種類 
一口にスマートポインタといっても何種類かある 
主にコピー/移動に関する動作が違う 
それぞれ適用できるシチュエーションが違ってくる 
スマートポインタ一覧 
名前所有権の移動move コピー 
std::auto ptr ○ × × 
std::unique ptr ○ ○ × 
boost::scoped ptr × × × 
boost::shared ptr × × ○ 
@NU-Pan 勉強会資料:スマートポインタ入門2014/07/10(木) 8 / 27
std::auto ptr 
特徴 
コピーの時に所有権"(=リソース解放の義務)が移譲される 
1つのリソースを指す有効なポインタは1個だけ 
使えるんならstd::unique ptr を使うべき 
使用例:戻り値にする 
1 // リソースを生成する関数 
2 std :: auto_ptr < ResouceClass > CreateResouce (...){ 
3 return std :: auto_ptr < ResouceClass >( new ResouceClass (...)); 
4 } 
5 
6 // リソースに何かの処理をする 
7 void SomeProcess (...){ 
8 // B u f f e r 1 へ所有権を移譲 
9 std :: auto_ptr < ResouceClass > Buffer1 = CreateResouce (...); 
10 
11 // B u f f e r 2 へ所有権を移譲( 見た目はコピーなのにB u f f e r 1 は無効! ) 
12 std :: auto_ptr < ResouceClass > Buffer2 = Buffer1 ; 
13 
14 // いろいろ処理する 
15 
16 } // <- a u t o _ p t r が自動的に解放してくれる 
@NU-Pan 勉強会資料:スマートポインタ入門2014/07/10(木) 9 / 27
std::unique ptr 
特徴 
std::auto ptr と大体同じだがmove" ができる 
使えるのはC++11 から(キーワード:右辺値参照、move セマンティクス) 
使用例:戻り値にする 
1 // リソースを生成する関数 
2 std :: unique_ptr < ResouceClass > CreateResouce (...){ 
3 return std :: unique_ptr < ResouceClass >( new ResouceClass (...)); 
4 } 
5 
6 // リソースに何かの処理をする 
7 void SomeProcess (...){ 
8 // B u f f e r 1 へ所有権を移譲( m o v e する) 
9 std :: unique_ptr < ResouceClass > Buffer1 = CreateResouce (...); 
10 
11 // コピー禁止なのでこれはできない-> 無効なB u f f e r 1 は発生しない 
12 // std :: unique_ptr < ResouceClass > Buffer2 = Buffer1 ; 
13 
14 // いろいろ処理する 
15 
16 } // <- u n i q u e _ p t r が自動的に解放してくれる 
@NU-Pan 勉強会資料:スマートポインタ入門2014/07/10(木) 10 / 27
boost::scoped ptr 
特徴 
コピーも移動も出来ない(禁止されている) 
あるスコープでのみ有効なポインタとして使える 
使用例:例外によるメモリリーク対策 
1 class SomeClass { 
2 private : 
3 ... 
4 public : 
5 SomeClass (...){ 
6 boost :: scoped_ptr < ResouceClass > Buffer (new ResouceClass (...)); 
7 
8 // 例外を投げるかも知れない危ない関数を呼ぶ 
9 DangerFunction (...); // <- 例外が起きた! 
10 } 
11 }; 
12 /*! 
13 1 . 例外がt h r o w される 
14 2 . コンストラクタを抜けようとする 
15 3 . コンストラクタを抜ける時に変数B u f f e r が削除される 
16 4 . n e w したR e s o u c e C l a s s のオブジェクトが開放される 
17 5 . リソース漏れを起こさずにコンストラクタを抜ける 
18 */ 
@NU-Pan 勉強会資料:スマートポインタ入門2014/07/10(木) 11 / 27
boost::shared ptr 
特徴 
1つのリソースの所有権をみんなで共有しましょうというポインタ 
最後に所有権を手放した人が責任を持ってリソース解放 
shared ptr の存在=所有権 
何がすごいのか? 
shared ptr が存在する間はリソースの寿命が保証される 
コピーができるのでSTL コンテナに入れることができる 
とにかくいろんな問題が解決する 
そのほかいろいろすごい(後述) 
@NU-Pan 勉強会資料:スマートポインタ入門2014/07/10(木) 12 / 27
すごいぞつよいぞshared ptr 
1 // ファクトリ関数 
2 boost :: shared_ptr < CResouce > CreateResouce (...){ 
3 // そのまま戻せる! 
4 return boost :: shared_ptr < CResouce >( new CResouce (...)); 
5 } 
6 
7 // リソースのポインタを持つクラス 
8 class CHoge { // コピー禁止しなくて良い! 
9 private : 
10 boost :: shared_ptr < CResouce > _pResouce ; 
11 
12 public : 
13 // コンストラクタでリソースのポインタを受け取る 
14 CHoge ( const boost :: shared_ptr < CResouce >& p_resouce ) 
15 : _pResouce ( p_resouce ){ 
16 } 
17 }; 
18 
19 // リソース利用側 
20 void SomeProcess (...){ 
21 // コピー可なのでコンテナに入れることができる! 
22 std :: map < std :: string , boost :: shared_ptr < CResouce > > ResouceMap ; 
23 ResouceMap [" hoge "] = CreateResouce (...); 
24 } 
@NU-Pan 勉強会資料:スマートポインタ入門2014/07/10(木) 13 / 27
shared ptr の使い方 
1 // 適当なクラス 
2 class CHoge { 
3 public : 
4 void Piyo (); 
5 }; 
6 
7 typedef boost :: shared_ptr <CHoge > sp_hoge ; 
8 typedef boost :: shared_ptr < const CHoge > scp_hoge ; 
9 
10 void f (){ 
11 sp_int pa( new CHoge ); 
12 
13 // 有効なポインタなら 
14 if( pa ){ 
15 pa -> Piyo (); 
16 CHoge b = *a; 
17 scp_hoge c = a; 
18 CHoge * raw_ptr = a. get (); 
19 } 
20 } 
@NU-Pan 勉強会資料:スマートポインタ入門2014/07/10(木) 14 / 27
shared ptr の実装 
参照カウンタ 
今時分が所有しているリソースは何人に所有されているか?" を表すカウ 
ンタを持っている(参照カウンタ) 
正確には参照カウンタへのポインタを持っている 
この参照カウンタを上下してリソースを解放すべきか判断する 
参照カウンタの動作 
最初は参照カウンタ=1 
shared ptr がコピーされると参照カウンタを+1 
shared ptr がデストラクトされると参照カウンタを-1 
参照カウンタを-1した時に0になったらリソース解放 
@NU-Pan 勉強会資料:スマートポインタ入門2014/07/10(木) 15 / 27
shared ptr の動作をトレースしてみる 
手順 
1 リソースを確保 
2 リソースへのポインタをshred ptr に渡す 
3 参照数カウント初期化 
4 shared ptr をコピー 
5 shared ptr を1つ削除 
6 shared ptr を0個に 
7 リソースの解放 
8 参照カウントの後始末 
@NU-Pan 勉強会資料:スマートポインタ入門2014/07/10(木) 16 / 27
shared ptr の弱点 
便利だけど弱点もある 
循環参照" が発生すると正しく解放されない 
連結リストの前後の要素を指すポインタには使えないということ 
参照数1のshared ptr が残ってしまう 
循環参照によるメモリリークのトーレス 
1 初期状態(循環参照が存在すると最終的にこうなる) 
2 1つ削除 
3 さらに1つ削除 
4 リソースが残ってしまった・・・ 
@NU-Pan 勉強会資料:スマートポインタ入門2014/07/10(木) 17 / 27
循環参照によるリソース漏れの解決 
weak ptr 
shared ptr の仲間 
所有権を持たないのでリソースの寿命には関係しない 
指し示すリソースが存在していればshared ptr に昇格できる 
実は参照カウンタとは別に弱参照カウンタ" というのも存在している 
shared ptr への昇格 
weak ptr はリソースへのポインタとカウンタへのポインタを持っている 
この2つの情報があればshared ptr を生成できる 
弱参照カウンタ 
weak ptr による参照数のカウンタ 
この参照カウンタと弱参照カウンタが両方0になった時カウンタがdelete 
される 
@NU-Pan 勉強会資料:スマートポインタ入門2014/07/10(木) 18 / 27
weak ptr の使い方 
1 class CResouce { 
2 ... 
3 }; 
4 
5 void f (){ 
6 boost :: shared_ptr < CResouce > sp(new CResouce ); 
7 boost :: weak_ptr < CResouce > wp(sp ); 
8 
9 // 参照カウント=1 , 弱参照カウント=1 
10 
11 boost :: shared_ptr < CResouce > p = wp. lock (); 
12 if(p){ 
13 // 確保成功= リソースはまだ生きていた 
14 // 参照カウント=2 , 弱参照カウント=1 
15 } else { 
16 // 確保失敗= リソースはすでに死んでいた 
17 // 参照カウント=0 , 弱参照カウント=1 
18 } 
19 } 
@NU-Pan 勉強会資料:スマートポインタ入門2014/07/10(木) 19 / 27
weak ptr の動作をトレースしてみる 
1 初期状態 
2 weak ptr 生成 
3 shared ptr 削除 
4 weak ptr 削除 
@NU-Pan 勉強会資料:スマートポインタ入門2014/07/10(木) 20 / 27
すごいぞshared ptr:デリータの指定 
デリータとは? 
shared ptr によって呼び出される解放関数のこと 
デフォルトでははdelete が呼び出される 
このデリータはコンストラクタで指定できる 
つまりdelete 以外の専用の解放関数が必要なリソースもshared ptr で管理で 
きる(すごい!) 
IplImage をshared ptr で管理してみる 
1 // I p l I m a g e をs h a r e d _ p t r に包んで生成するファクトリ関数 
2 boost :: shared_ptr < IplImage > CreateIplImage (int w, int h, int c){ 
3 IplImage * pImage = cvCreateImage ( cvSize (w, h), IPL_DEPTH_8U , c); 
4 return boost :: shared_ptr < IplImage >( pImage , & cvReleaseImage ); 
5 } 
@NU-Pan 勉強会資料:スマートポインタ入門2014/07/10(木) 21 / 27
つよいぞshared ptr:バイナリを超えても大丈夫 
考える状況 
ライブラリA とB をリンクしてプログラムをコンパイルした 
ライブラリA 内でshared ptr を生成した 
生成したshared ptr をライブラリB で実装されているクラスに渡した 
ライブラリB でカウントが0になってデリータが呼び出された 
もし生ポインタなら 
ライブラリA のnew で生成 
ライブラリB のdelete で削除 
ライブラリA のnew とライブラリB のdelete がちゃんと対応しているとは 
限らない! 
▶ ライブラリA とB でリンクしてあるmalloc の実装が違う 
▶ リリースビルドとデバッグビルドが混在している 
この場合正常にdelete される保証はない・・・ 
@NU-Pan 勉強会資料:スマートポインタ入門2014/07/10(木) 22 / 27
つよいぞshared ptr:バイナリを超えても大丈夫 
shared ptr なら! 
ライブラリA でshared ptr を生成した時にどのdelete を使うかは決まる 
ライブラリB でリソースを削除する時にライブラリA で設定したdelete が 
呼び出される! 
ちゃんと対応したnew/delete なのでOK! 
@NU-Pan 勉強会資料:スマートポインタ入門2014/07/10(木) 23 / 27
ヤバいぞshared ptr:マルチスレッドでもOK 
マルチスレッドでshared ptr 
スレッドA とB に1つのshared ptr を渡す(ここのコピーはmutex で保護) 
親スレッドでshared ptr を削除 
スレッドA とB で時間的に同時にshared ptr を削除 
正しくリソースが解放される? 
atomic なカウンタ 
shared ptr のカウンタはatomic なので時間的に同時にカウンタ操作されて 
もOK! 
ただし、一つのshared ptr に同時に読み書きをする場合はmutex で排他制 
御する必要がある(これは生ポインタでも同じ) 
atmic なカウンタの代償 
カウント操作が重たい! 
逐次一貫性の保持のためにCPU の最適化に制限がかかるので 
@NU-Pan 勉強会資料:スマートポインタ入門2014/07/10(木) 24 / 27
スマート配列 
配列用shared ptr 
new []" されたポインタはdelete []" しなければならない 
shared ptr ではdelete" が呼び出される 
shared array ならdelete []" を呼び出してくれる! 
添字演算子[]" も定義されている 
scoped array も存在する 
ちなみに、バッファがほしい時はstd::vector を使うべきなのでscoped array 
の出番は少ない 
@NU-Pan 勉強会資料:スマートポインタ入門2014/07/10(木) 25 / 27
intrusive ptr 
クラス備え付けのカウント機構を使う 
Microsoft のCOM みたいにクラスにそもそも参照カウント機構が備わって 
いる場合がある 
その場合はカウント機構を使いたい・・・ 
boost::intrusive ptr ならクラス備え付けのカウント機構を使ってくれる 
アロケーションの効率はよい(カウンタをnew しなくていい)が、weak ptr 
を取れない 
@NU-Pan 勉強会資料:スマートポインタ入門2014/07/10(木) 26 / 27
まとめ 
説明したこと 
生ポインタは強力だけど危ない 
生ポインタは別の手段で置き換える事を考えよう 
スマートポインタの使用を検討しよう 
shared ptr はとても便利! 
大事なこと 
リソースを管理しようと思ったらスマートポインタ 
shared ptr はとにかく強力でいろんな状況に適用できる 
気をつけること 
スマートポインタの種類によって解放タイミングや挙動は違う 
shared ptr は循環参照が起きないよう注意 
@NU-Pan 勉強会資料:スマートポインタ入門2014/07/10(木) 27 / 27

More Related Content

What's hot

Lisp tutorial for Pythonista : Day 1
Lisp tutorial for Pythonista : Day 1Lisp tutorial for Pythonista : Day 1
Lisp tutorial for Pythonista : Day 1
Ransui Iso
 
エキ Py 読書会02 2010/9/7
エキ Py 読書会02 2010/9/7エキ Py 読書会02 2010/9/7
エキ Py 読書会02 2010/9/7
Tetsuya Morimoto
 
PyCon2020 Pythonで競プロをしよう! 〜入門者が知っておくべき高速化Tips〜
PyCon2020 Pythonで競プロをしよう! 〜入門者が知っておくべき高速化Tips〜PyCon2020 Pythonで競プロをしよう! 〜入門者が知っておくべき高速化Tips〜
PyCon2020 Pythonで競プロをしよう! 〜入門者が知っておくべき高速化Tips〜
Kosaku Ono
 

What's hot (20)

Python 3.6 リリースパーティー 発表資料
Python 3.6 リリースパーティー 発表資料Python 3.6 リリースパーティー 発表資料
Python 3.6 リリースパーティー 発表資料
 
PEP8を読んでみよう
PEP8を読んでみようPEP8を読んでみよう
PEP8を読んでみよう
 
Google Developer Day 2010 Japan: プログラミング言語 Go (鵜飼 文敏)
Google Developer Day 2010 Japan: プログラミング言語 Go (鵜飼 文敏)Google Developer Day 2010 Japan: プログラミング言語 Go (鵜飼 文敏)
Google Developer Day 2010 Japan: プログラミング言語 Go (鵜飼 文敏)
 
Python入門
Python入門Python入門
Python入門
 
Cython intro prelerease
Cython intro prelereaseCython intro prelerease
Cython intro prelerease
 
STLの型の使い分け(ダイジェスト版) @ Sapporo.cpp 第7回勉強会 (2014.10.18)
STLの型の使い分け(ダイジェスト版) @ Sapporo.cpp 第7回勉強会 (2014.10.18)STLの型の使い分け(ダイジェスト版) @ Sapporo.cpp 第7回勉強会 (2014.10.18)
STLの型の使い分け(ダイジェスト版) @ Sapporo.cpp 第7回勉強会 (2014.10.18)
 
boost tour 1.48.0 all
boost tour 1.48.0 allboost tour 1.48.0 all
boost tour 1.48.0 all
 
20170131 python3 6 PEP526
20170131 python3 6 PEP526 20170131 python3 6 PEP526
20170131 python3 6 PEP526
 
科学技術計算関連Pythonパッケージの概要
科学技術計算関連Pythonパッケージの概要科学技術計算関連Pythonパッケージの概要
科学技術計算関連Pythonパッケージの概要
 
Lisp tutorial for Pythonista : Day 1
Lisp tutorial for Pythonista : Day 1Lisp tutorial for Pythonista : Day 1
Lisp tutorial for Pythonista : Day 1
 
中3女子が狂える本当に気持ちのいい constexpr
中3女子が狂える本当に気持ちのいい constexpr中3女子が狂える本当に気持ちのいい constexpr
中3女子が狂える本当に気持ちのいい constexpr
 
2013.07.15 はじパタlt scikit-learnで始める機械学習
2013.07.15 はじパタlt scikit-learnで始める機械学習2013.07.15 はじパタlt scikit-learnで始める機械学習
2013.07.15 はじパタlt scikit-learnで始める機械学習
 
エキ Py 読書会02 2010/9/7
エキ Py 読書会02 2010/9/7エキ Py 読書会02 2010/9/7
エキ Py 読書会02 2010/9/7
 
Boost tour 1.60.0 merge
Boost tour 1.60.0 mergeBoost tour 1.60.0 merge
Boost tour 1.60.0 merge
 
Scalaのオブジェクトの話
Scalaのオブジェクトの話Scalaのオブジェクトの話
Scalaのオブジェクトの話
 
PyCon2020 Pythonで競プロをしよう! 〜入門者が知っておくべき高速化Tips〜
PyCon2020 Pythonで競プロをしよう! 〜入門者が知っておくべき高速化Tips〜PyCon2020 Pythonで競プロをしよう! 〜入門者が知っておくべき高速化Tips〜
PyCon2020 Pythonで競プロをしよう! 〜入門者が知っておくべき高速化Tips〜
 
core dumpでcode golf
core dumpでcode golfcore dumpでcode golf
core dumpでcode golf
 
Pythonデータ分析 第3回勉強会資料 8章
Pythonデータ分析 第3回勉強会資料 8章 Pythonデータ分析 第3回勉強会資料 8章
Pythonデータ分析 第3回勉強会資料 8章
 
Boost Tour 1.50.0 All
Boost Tour 1.50.0 AllBoost Tour 1.50.0 All
Boost Tour 1.50.0 All
 
High performance python computing for data science
High performance python computing for data scienceHigh performance python computing for data science
High performance python computing for data science
 

Viewers also liked

Boost勉強会 #10 ディスカッションまとめ
Boost勉強会 #10 ディスカッションまとめBoost勉強会 #10 ディスカッションまとめ
Boost勉強会 #10 ディスカッションまとめ
Sigureya
 
3D CADと3Dプリンタ体験セミナー #1
3D CADと3Dプリンタ体験セミナー #13D CADと3Dプリンタ体験セミナー #1
3D CADと3Dプリンタ体験セミナー #1
Kou Ouchi
 

Viewers also liked (20)

Techno TUT Lecture 2014/11/14
Techno TUT Lecture 2014/11/14Techno TUT Lecture 2014/11/14
Techno TUT Lecture 2014/11/14
 
Boost study meeting opening 4
Boost study meeting opening 4Boost study meeting opening 4
Boost study meeting opening 4
 
CG基礎3 メタリンク
CG基礎3 メタリンクCG基礎3 メタリンク
CG基礎3 メタリンク
 
ABC2015 Summer LT
ABC2015 Summer LTABC2015 Summer LT
ABC2015 Summer LT
 
boost - std - C#
boost - std - C#boost - std - C#
boost - std - C#
 
The Earth is not flat; but it's not round either (Geography on Boost.Geometry)
The Earth is not flat; but it's not round either (Geography on Boost.Geometry)The Earth is not flat; but it's not round either (Geography on Boost.Geometry)
The Earth is not flat; but it's not round either (Geography on Boost.Geometry)
 
Boost勉強会 #10 ディスカッションまとめ
Boost勉強会 #10 ディスカッションまとめBoost勉強会 #10 ディスカッションまとめ
Boost勉強会 #10 ディスカッションまとめ
 
Glfw3,OpenGL,GUI
Glfw3,OpenGL,GUI Glfw3,OpenGL,GUI
Glfw3,OpenGL,GUI
 
boost and c++11
boost and c++11boost and c++11
boost and c++11
 
3DCAD@VDI活用とCADデータ管理のロードマップ
3DCAD@VDI活用とCADデータ管理のロードマップ3DCAD@VDI活用とCADデータ管理のロードマップ
3DCAD@VDI活用とCADデータ管理のロードマップ
 
ゲーム開発経営ゲーム
ゲーム開発経営ゲームゲーム開発経営ゲーム
ゲーム開発経営ゲーム
 
Boost container feature
Boost container featureBoost container feature
Boost container feature
 
Boost Tour 1_58_0 merge
Boost Tour 1_58_0 mergeBoost Tour 1_58_0 merge
Boost Tour 1_58_0 merge
 
Boost tour 1.60.0
Boost tour 1.60.0Boost tour 1.60.0
Boost tour 1.60.0
 
3D CADと3Dプリンタ体験セミナー #1
3D CADと3Dプリンタ体験セミナー #13D CADと3Dプリンタ体験セミナー #1
3D CADと3Dプリンタ体験セミナー #1
 
Unity MeshとColliderについて
Unity MeshとColliderについてUnity MeshとColliderについて
Unity MeshとColliderについて
 
Boost apps ver1.0
Boost apps ver1.0Boost apps ver1.0
Boost apps ver1.0
 
ゲームアプリの数学@GREE GameDevelopers' Meetup
ゲームアプリの数学@GREE GameDevelopers' Meetupゲームアプリの数学@GREE GameDevelopers' Meetup
ゲームアプリの数学@GREE GameDevelopers' Meetup
 
BoostAsioで可読性を求めるのは間違っているだろうか
BoostAsioで可読性を求めるのは間違っているだろうかBoostAsioで可読性を求めるのは間違っているだろうか
BoostAsioで可読性を求めるのは間違っているだろうか
 
Study3 boost
Study3 boostStudy3 boost
Study3 boost
 

Similar to boost::shared_ptr tutorial

Unity2015_No10_~UGUI&Audio~
Unity2015_No10_~UGUI&Audio~Unity2015_No10_~UGUI&Audio~
Unity2015_No10_~UGUI&Audio~
CHY72
 
Replace Output Iterator and Extend Range JP
Replace Output Iterator and Extend Range JPReplace Output Iterator and Extend Range JP
Replace Output Iterator and Extend Range JP
Akira Takahashi
 
Ryuの遊び方(pica8も併せてもっと楽しく)(2014/1/23修正版)
Ryuの遊び方(pica8も併せてもっと楽しく)(2014/1/23修正版)Ryuの遊び方(pica8も併せてもっと楽しく)(2014/1/23修正版)
Ryuの遊び方(pica8も併せてもっと楽しく)(2014/1/23修正版)
hiroshi oshiba
 
20130329 rtm3
20130329 rtm320130329 rtm3
20130329 rtm3
openrtm
 
おまえらこのライブラリ使ってないの? m9 (2013-07)
おまえらこのライブラリ使ってないの? m9	(2013-07)おまえらこのライブラリ使ってないの? m9	(2013-07)
おまえらこのライブラリ使ってないの? m9 (2013-07)
Toru Furukawa
 

Similar to boost::shared_ptr tutorial (20)

C++ ポインタ ブートキャンプ
C++ ポインタ ブートキャンプC++ ポインタ ブートキャンプ
C++ ポインタ ブートキャンプ
 
研究生のためのC++ no.2
研究生のためのC++ no.2研究生のためのC++ no.2
研究生のためのC++ no.2
 
研究会20140618:進捗と闇Pythonistaのワンライナーテクニックを少々
研究会20140618:進捗と闇Pythonistaのワンライナーテクニックを少々研究会20140618:進捗と闇Pythonistaのワンライナーテクニックを少々
研究会20140618:進捗と闇Pythonistaのワンライナーテクニックを少々
 
Unity2015_No10_~UGUI&Audio~
Unity2015_No10_~UGUI&Audio~Unity2015_No10_~UGUI&Audio~
Unity2015_No10_~UGUI&Audio~
 
Replace Output Iterator and Extend Range JP
Replace Output Iterator and Extend Range JPReplace Output Iterator and Extend Range JP
Replace Output Iterator and Extend Range JP
 
今日からできる!簡単 .NET 高速化 Tips
今日からできる!簡単 .NET 高速化 Tips今日からできる!簡単 .NET 高速化 Tips
今日からできる!簡単 .NET 高速化 Tips
 
Ryuの遊び方(pica8も併せてもっと楽しく)(2014/1/23修正版)
Ryuの遊び方(pica8も併せてもっと楽しく)(2014/1/23修正版)Ryuの遊び方(pica8も併せてもっと楽しく)(2014/1/23修正版)
Ryuの遊び方(pica8も併せてもっと楽しく)(2014/1/23修正版)
 
20130329 rtm3
20130329 rtm320130329 rtm3
20130329 rtm3
 
わんくま同盟大阪勉強会#61
わんくま同盟大阪勉強会#61わんくま同盟大阪勉強会#61
わんくま同盟大阪勉強会#61
 
おまえらこのライブラリ使ってないの? m9 (2013-07)
おまえらこのライブラリ使ってないの? m9	(2013-07)おまえらこのライブラリ使ってないの? m9	(2013-07)
おまえらこのライブラリ使ってないの? m9 (2013-07)
 
Pythonはどうやってlen関数で長さを手にいれているの?
Pythonはどうやってlen関数で長さを手にいれているの?Pythonはどうやってlen関数で長さを手にいれているの?
Pythonはどうやってlen関数で長さを手にいれているの?
 
Introduction to Chainer (LL Ring Recursive)
Introduction to Chainer (LL Ring Recursive)Introduction to Chainer (LL Ring Recursive)
Introduction to Chainer (LL Ring Recursive)
 
「Python言語」はじめの一歩 / First step of Python / 2016 Jan 12
「Python言語」はじめの一歩 / First step of Python / 2016 Jan 12「Python言語」はじめの一歩 / First step of Python / 2016 Jan 12
「Python言語」はじめの一歩 / First step of Python / 2016 Jan 12
 
Ansible入門...?
Ansible入門...?Ansible入門...?
Ansible入門...?
 
今年使ってみて良かった、Pythonモジュール、パッケージ、ツール
今年使ってみて良かった、Pythonモジュール、パッケージ、ツール今年使ってみて良かった、Pythonモジュール、パッケージ、ツール
今年使ってみて良かった、Pythonモジュール、パッケージ、ツール
 
Introduction to Chainer and CuPy
Introduction to Chainer and CuPyIntroduction to Chainer and CuPy
Introduction to Chainer and CuPy
 
2011.09.18 v7から始めるunix まとめ
2011.09.18 v7から始めるunix まとめ2011.09.18 v7から始めるunix まとめ
2011.09.18 v7から始めるunix まとめ
 
Twitter sphere of #twitter4j #twtr_hack
Twitter sphere of #twitter4j #twtr_hackTwitter sphere of #twitter4j #twtr_hack
Twitter sphere of #twitter4j #twtr_hack
 
I phoneアプリ入門 第5回
I phoneアプリ入門 第5回I phoneアプリ入門 第5回
I phoneアプリ入門 第5回
 
ひのきのぼうだけで全クリ目指す
ひのきのぼうだけで全クリ目指すひのきのぼうだけで全クリ目指す
ひのきのぼうだけで全クリ目指す
 

boost::shared_ptr tutorial

  • 1. 勉強会資料:スマートポインタ入門 @NU-Pan 2014/07/10(木) @NU-Pan 勉強会資料:スマートポインタ入門2014/07/10(木) 1 / 27
  • 2. 生ポインタは便利 ポインタの偉大な点 他の変数を指し示せる変数である 演算できる 無効値であるNULL が存在する 非常に低コスト(実体は64bit or 32bit の符号なし整数ですから!) 例えば:線形探索 1 // 線形探索関数 2 template < typename T> 3 T* Search (T* begin , T* end , T value ){ 4 for(T* i= begin ; i!= end ; ++i){ 5 if (*i== value ){ 6 return i; 7 } 8 } 9 return NULL ; 10 } 11 12 // こう使う 13 double Array [10] = {...}; 14 double * Result = Search (Array , Array +10 , 810); @NU-Pan 勉強会資料:スマートポインタ入門2014/07/10(木) 2 / 27
  • 3. 生ポインタは危ない 1 // 画像を作る関数 2 uint8_t * CreateImage (int w, int h, int c){ 3 uint8_t * Image = new uint8_t [w*h*c]; 4 5 uint8_t * Pixel = Image ; 6 for(int i =0; i<w*h*c; ++i){ // <- バッファオーバーラン! 7 memset (Pixel , 127 , c); 8 Pixel += c; 9 } 10 11 return Image ; 12 } 13 14 // 画像に何かの処理をする 15 void SomeProcess ( uint8_t * image , int w, int h, int c){ 16 uint8_t * Buffer = CreateImage (w, h, c); 17 18 // 何かの処理をいっぱい書く 19 20 }// <- メモリリーク! 確かに便利だが危険も伴う できればこういうリスクは抱えたくない @NU-Pan 勉強会資料:スマートポインタ入門2014/07/10(木) 3 / 27
  • 4. 生ポインタの扱い方 基本的な方針 速度が大事なところではオーバーヘッドの少ない生ポインタ 速度よりも楽ができること" が大事なところではより安全な別の手段を 使う 実行速度と安全性のトレードオフを考えて使いましょうということ 例えば:引数をconst 参照で置き換え 1 // コピー出来ないクラス 2 class FileWriter { 3 private : 4 FileWriter ( const FileWriter &); 5 SomeClass & operator =( const FileWriter &); 6 public : 7 // いろいろ 8 }; 9 10 // ポインタでもとれるが参照の方が安全 11 void SomeProcess ( FileWriter & writer , ...){ 12 // なにか処理する 13 } @NU-Pan 勉強会資料:スマートポインタ入門2014/07/10(木) 4 / 27
  • 5. 生ポインタの扱い方 例えば:関数の戻り値をboost.optional にする 1 // 答えが出ないかも知れない小難しい計算をする 2 boost :: optional <int > SomeProcess (...){ 3 . 4 . 5 . 6 // 途中で計算が破綻した! 7 if (...){ 8 return boost :: optional <int >(); // 明確な無効値を返却 9 } 10 . 11 . 12 . 13 } 14 15 // こう使う 16 boost :: optional <int > Result = SomeProcess (...); 17 if( Result ){ // そのまま真理値として有効/ 無効を判別できる 18 int value = * Result ; // 値は* でとれる 19 } else { 20 // 失敗したのでエラー処理 21 } @NU-Pan 勉強会資料:スマートポインタ入門2014/07/10(木) 5 / 27
  • 6. 生ポインタの扱い方 例えば:ポインタをクラスで包んでリソース管理? ・ ・ ・ ・ ・ ・ 管理"って簡単に言うけど具体的に何するんですか? @NU-Pan 勉強会資料:スマートポインタ入門2014/07/10(木) 6 / 27
  • 7. リソース管理クラスis 何 管理" に何を求めているのか? 自分で確保したリソースの後始末をいい感じに" やってほしい いい感じ" とは適切なタイミング" でリソースを解放してくれること 適切なタイミング" とは大抵の場合はリソースが不要になったタイミング リソース管理クラスとはつまり 生のポインタを格納 ポインタの示すリソースが不要になったら自動で解放してくれる そんな機能を持ったクラスのこと そういうクラスのことをスマートポインタという @NU-Pan 勉強会資料:スマートポインタ入門2014/07/10(木) 7 / 27
  • 8. スマートポインタ スマートポインタの種類 一口にスマートポインタといっても何種類かある 主にコピー/移動に関する動作が違う それぞれ適用できるシチュエーションが違ってくる スマートポインタ一覧 名前所有権の移動move コピー std::auto ptr ○ × × std::unique ptr ○ ○ × boost::scoped ptr × × × boost::shared ptr × × ○ @NU-Pan 勉強会資料:スマートポインタ入門2014/07/10(木) 8 / 27
  • 9. std::auto ptr 特徴 コピーの時に所有権"(=リソース解放の義務)が移譲される 1つのリソースを指す有効なポインタは1個だけ 使えるんならstd::unique ptr を使うべき 使用例:戻り値にする 1 // リソースを生成する関数 2 std :: auto_ptr < ResouceClass > CreateResouce (...){ 3 return std :: auto_ptr < ResouceClass >( new ResouceClass (...)); 4 } 5 6 // リソースに何かの処理をする 7 void SomeProcess (...){ 8 // B u f f e r 1 へ所有権を移譲 9 std :: auto_ptr < ResouceClass > Buffer1 = CreateResouce (...); 10 11 // B u f f e r 2 へ所有権を移譲( 見た目はコピーなのにB u f f e r 1 は無効! ) 12 std :: auto_ptr < ResouceClass > Buffer2 = Buffer1 ; 13 14 // いろいろ処理する 15 16 } // <- a u t o _ p t r が自動的に解放してくれる @NU-Pan 勉強会資料:スマートポインタ入門2014/07/10(木) 9 / 27
  • 10. std::unique ptr 特徴 std::auto ptr と大体同じだがmove" ができる 使えるのはC++11 から(キーワード:右辺値参照、move セマンティクス) 使用例:戻り値にする 1 // リソースを生成する関数 2 std :: unique_ptr < ResouceClass > CreateResouce (...){ 3 return std :: unique_ptr < ResouceClass >( new ResouceClass (...)); 4 } 5 6 // リソースに何かの処理をする 7 void SomeProcess (...){ 8 // B u f f e r 1 へ所有権を移譲( m o v e する) 9 std :: unique_ptr < ResouceClass > Buffer1 = CreateResouce (...); 10 11 // コピー禁止なのでこれはできない-> 無効なB u f f e r 1 は発生しない 12 // std :: unique_ptr < ResouceClass > Buffer2 = Buffer1 ; 13 14 // いろいろ処理する 15 16 } // <- u n i q u e _ p t r が自動的に解放してくれる @NU-Pan 勉強会資料:スマートポインタ入門2014/07/10(木) 10 / 27
  • 11. boost::scoped ptr 特徴 コピーも移動も出来ない(禁止されている) あるスコープでのみ有効なポインタとして使える 使用例:例外によるメモリリーク対策 1 class SomeClass { 2 private : 3 ... 4 public : 5 SomeClass (...){ 6 boost :: scoped_ptr < ResouceClass > Buffer (new ResouceClass (...)); 7 8 // 例外を投げるかも知れない危ない関数を呼ぶ 9 DangerFunction (...); // <- 例外が起きた! 10 } 11 }; 12 /*! 13 1 . 例外がt h r o w される 14 2 . コンストラクタを抜けようとする 15 3 . コンストラクタを抜ける時に変数B u f f e r が削除される 16 4 . n e w したR e s o u c e C l a s s のオブジェクトが開放される 17 5 . リソース漏れを起こさずにコンストラクタを抜ける 18 */ @NU-Pan 勉強会資料:スマートポインタ入門2014/07/10(木) 11 / 27
  • 12. boost::shared ptr 特徴 1つのリソースの所有権をみんなで共有しましょうというポインタ 最後に所有権を手放した人が責任を持ってリソース解放 shared ptr の存在=所有権 何がすごいのか? shared ptr が存在する間はリソースの寿命が保証される コピーができるのでSTL コンテナに入れることができる とにかくいろんな問題が解決する そのほかいろいろすごい(後述) @NU-Pan 勉強会資料:スマートポインタ入門2014/07/10(木) 12 / 27
  • 13. すごいぞつよいぞshared ptr 1 // ファクトリ関数 2 boost :: shared_ptr < CResouce > CreateResouce (...){ 3 // そのまま戻せる! 4 return boost :: shared_ptr < CResouce >( new CResouce (...)); 5 } 6 7 // リソースのポインタを持つクラス 8 class CHoge { // コピー禁止しなくて良い! 9 private : 10 boost :: shared_ptr < CResouce > _pResouce ; 11 12 public : 13 // コンストラクタでリソースのポインタを受け取る 14 CHoge ( const boost :: shared_ptr < CResouce >& p_resouce ) 15 : _pResouce ( p_resouce ){ 16 } 17 }; 18 19 // リソース利用側 20 void SomeProcess (...){ 21 // コピー可なのでコンテナに入れることができる! 22 std :: map < std :: string , boost :: shared_ptr < CResouce > > ResouceMap ; 23 ResouceMap [" hoge "] = CreateResouce (...); 24 } @NU-Pan 勉強会資料:スマートポインタ入門2014/07/10(木) 13 / 27
  • 14. shared ptr の使い方 1 // 適当なクラス 2 class CHoge { 3 public : 4 void Piyo (); 5 }; 6 7 typedef boost :: shared_ptr <CHoge > sp_hoge ; 8 typedef boost :: shared_ptr < const CHoge > scp_hoge ; 9 10 void f (){ 11 sp_int pa( new CHoge ); 12 13 // 有効なポインタなら 14 if( pa ){ 15 pa -> Piyo (); 16 CHoge b = *a; 17 scp_hoge c = a; 18 CHoge * raw_ptr = a. get (); 19 } 20 } @NU-Pan 勉強会資料:スマートポインタ入門2014/07/10(木) 14 / 27
  • 15. shared ptr の実装 参照カウンタ 今時分が所有しているリソースは何人に所有されているか?" を表すカウ ンタを持っている(参照カウンタ) 正確には参照カウンタへのポインタを持っている この参照カウンタを上下してリソースを解放すべきか判断する 参照カウンタの動作 最初は参照カウンタ=1 shared ptr がコピーされると参照カウンタを+1 shared ptr がデストラクトされると参照カウンタを-1 参照カウンタを-1した時に0になったらリソース解放 @NU-Pan 勉強会資料:スマートポインタ入門2014/07/10(木) 15 / 27
  • 16. shared ptr の動作をトレースしてみる 手順 1 リソースを確保 2 リソースへのポインタをshred ptr に渡す 3 参照数カウント初期化 4 shared ptr をコピー 5 shared ptr を1つ削除 6 shared ptr を0個に 7 リソースの解放 8 参照カウントの後始末 @NU-Pan 勉強会資料:スマートポインタ入門2014/07/10(木) 16 / 27
  • 17. shared ptr の弱点 便利だけど弱点もある 循環参照" が発生すると正しく解放されない 連結リストの前後の要素を指すポインタには使えないということ 参照数1のshared ptr が残ってしまう 循環参照によるメモリリークのトーレス 1 初期状態(循環参照が存在すると最終的にこうなる) 2 1つ削除 3 さらに1つ削除 4 リソースが残ってしまった・・・ @NU-Pan 勉強会資料:スマートポインタ入門2014/07/10(木) 17 / 27
  • 18. 循環参照によるリソース漏れの解決 weak ptr shared ptr の仲間 所有権を持たないのでリソースの寿命には関係しない 指し示すリソースが存在していればshared ptr に昇格できる 実は参照カウンタとは別に弱参照カウンタ" というのも存在している shared ptr への昇格 weak ptr はリソースへのポインタとカウンタへのポインタを持っている この2つの情報があればshared ptr を生成できる 弱参照カウンタ weak ptr による参照数のカウンタ この参照カウンタと弱参照カウンタが両方0になった時カウンタがdelete される @NU-Pan 勉強会資料:スマートポインタ入門2014/07/10(木) 18 / 27
  • 19. weak ptr の使い方 1 class CResouce { 2 ... 3 }; 4 5 void f (){ 6 boost :: shared_ptr < CResouce > sp(new CResouce ); 7 boost :: weak_ptr < CResouce > wp(sp ); 8 9 // 参照カウント=1 , 弱参照カウント=1 10 11 boost :: shared_ptr < CResouce > p = wp. lock (); 12 if(p){ 13 // 確保成功= リソースはまだ生きていた 14 // 参照カウント=2 , 弱参照カウント=1 15 } else { 16 // 確保失敗= リソースはすでに死んでいた 17 // 参照カウント=0 , 弱参照カウント=1 18 } 19 } @NU-Pan 勉強会資料:スマートポインタ入門2014/07/10(木) 19 / 27
  • 20. weak ptr の動作をトレースしてみる 1 初期状態 2 weak ptr 生成 3 shared ptr 削除 4 weak ptr 削除 @NU-Pan 勉強会資料:スマートポインタ入門2014/07/10(木) 20 / 27
  • 21. すごいぞshared ptr:デリータの指定 デリータとは? shared ptr によって呼び出される解放関数のこと デフォルトでははdelete が呼び出される このデリータはコンストラクタで指定できる つまりdelete 以外の専用の解放関数が必要なリソースもshared ptr で管理で きる(すごい!) IplImage をshared ptr で管理してみる 1 // I p l I m a g e をs h a r e d _ p t r に包んで生成するファクトリ関数 2 boost :: shared_ptr < IplImage > CreateIplImage (int w, int h, int c){ 3 IplImage * pImage = cvCreateImage ( cvSize (w, h), IPL_DEPTH_8U , c); 4 return boost :: shared_ptr < IplImage >( pImage , & cvReleaseImage ); 5 } @NU-Pan 勉強会資料:スマートポインタ入門2014/07/10(木) 21 / 27
  • 22. つよいぞshared ptr:バイナリを超えても大丈夫 考える状況 ライブラリA とB をリンクしてプログラムをコンパイルした ライブラリA 内でshared ptr を生成した 生成したshared ptr をライブラリB で実装されているクラスに渡した ライブラリB でカウントが0になってデリータが呼び出された もし生ポインタなら ライブラリA のnew で生成 ライブラリB のdelete で削除 ライブラリA のnew とライブラリB のdelete がちゃんと対応しているとは 限らない! ▶ ライブラリA とB でリンクしてあるmalloc の実装が違う ▶ リリースビルドとデバッグビルドが混在している この場合正常にdelete される保証はない・・・ @NU-Pan 勉強会資料:スマートポインタ入門2014/07/10(木) 22 / 27
  • 23. つよいぞshared ptr:バイナリを超えても大丈夫 shared ptr なら! ライブラリA でshared ptr を生成した時にどのdelete を使うかは決まる ライブラリB でリソースを削除する時にライブラリA で設定したdelete が 呼び出される! ちゃんと対応したnew/delete なのでOK! @NU-Pan 勉強会資料:スマートポインタ入門2014/07/10(木) 23 / 27
  • 24. ヤバいぞshared ptr:マルチスレッドでもOK マルチスレッドでshared ptr スレッドA とB に1つのshared ptr を渡す(ここのコピーはmutex で保護) 親スレッドでshared ptr を削除 スレッドA とB で時間的に同時にshared ptr を削除 正しくリソースが解放される? atomic なカウンタ shared ptr のカウンタはatomic なので時間的に同時にカウンタ操作されて もOK! ただし、一つのshared ptr に同時に読み書きをする場合はmutex で排他制 御する必要がある(これは生ポインタでも同じ) atmic なカウンタの代償 カウント操作が重たい! 逐次一貫性の保持のためにCPU の最適化に制限がかかるので @NU-Pan 勉強会資料:スマートポインタ入門2014/07/10(木) 24 / 27
  • 25. スマート配列 配列用shared ptr new []" されたポインタはdelete []" しなければならない shared ptr ではdelete" が呼び出される shared array ならdelete []" を呼び出してくれる! 添字演算子[]" も定義されている scoped array も存在する ちなみに、バッファがほしい時はstd::vector を使うべきなのでscoped array の出番は少ない @NU-Pan 勉強会資料:スマートポインタ入門2014/07/10(木) 25 / 27
  • 26. intrusive ptr クラス備え付けのカウント機構を使う Microsoft のCOM みたいにクラスにそもそも参照カウント機構が備わって いる場合がある その場合はカウント機構を使いたい・・・ boost::intrusive ptr ならクラス備え付けのカウント機構を使ってくれる アロケーションの効率はよい(カウンタをnew しなくていい)が、weak ptr を取れない @NU-Pan 勉強会資料:スマートポインタ入門2014/07/10(木) 26 / 27
  • 27. まとめ 説明したこと 生ポインタは強力だけど危ない 生ポインタは別の手段で置き換える事を考えよう スマートポインタの使用を検討しよう shared ptr はとても便利! 大事なこと リソースを管理しようと思ったらスマートポインタ shared ptr はとにかく強力でいろんな状況に適用できる 気をつけること スマートポインタの種類によって解放タイミングや挙動は違う shared ptr は循環参照が起きないよう注意 @NU-Pan 勉強会資料:スマートポインタ入門2014/07/10(木) 27 / 27