Torus2 > とりあえずスマートポインタの導入

Selene1.0で使われているインターフェース(簡単に言えばIで始まるクラス)では
AddRef,Releaseメンバ関数が定義されていますが、
おそらく、これは参照カウンタ形式でインターフェースを管理できるようにしているためです
ここではその管理の上で使われるAddRef、Release関数をある程度自動でやれるようにするクラスを作りました
ぶっちゃけるとこんなクラスいらない(ググるといっぱい出てくるくらい陳腐)のですが、とりあえず安全性のため作っときます

参照カウンタ形式

ポインタを安全に管理するための方法のひとつで、
たとえば、
  1. int* a=new int;
  2. *a=5;
  3. int* b=a;
  4. int* c=a;
  5. delete a;
  6. *c=1; // error
  7.  
はエラーになるのは明らかです(cが示す実体は"delete a"で開放されてしまっています)
エラーにならないようにする方法の一つが参照カウンタ形式になります

この場合は1つの実体を3つのポインタ(a,b,c)で参照しているのですが、
この実体を2つの参照ポインタを消去しても残っていて、3つめの参照ポインタを消したときに初めて実体が消えるようにします
(この場合は参照ポインタそのものじゃなくて、参照ポインタの様に動くクラスみたいな感じになるんですけど)
そうすれば、上のようにaだけを消したつもりなのに、cまで消えちゃうなんて事がなくなります

どうするかというと、どれだけポインタとして参照されているのかを示す"参照カウンタ"を用意します
それが0になった時点で初めて実体を開放するようにすればいいです
簡単な例で説明すると(完全にエラーだし厳密性無視だけど・感じだけつかんでくれたら助かります)
  1. int* a=new int; // 参照カウンタ:0→1
  2. *a=5;
  3. int* b=a; // 参照カウンタ:1→2
  4. int* c=a; // 参照カウンタ:2→3
  5. delete a; // 参照カウンタ:3→2
  6. delete b; // 参照カウンタ:2→1
  7. delete c; // 参照カウンタ:1→0(開放)
  8.  
のように動く参照カウンタがあれば、問題を解決できます
("delete a"のあとでもcには実体があるので代入などの操作ができる)

そして、Seleneのインターフェースの場合、参照カウンタを増やす関数がAddRef関数,
減らしてカウンタが0になったら開放する関数がRelease関数にあたります
ただこのままだと、たとえば、(これも適当、IInterfaceもCreateInterfaceもたぶんない・感じだけつかんでくれたら助かります)
  1. IInterface* a=CreateInterface(); // 参照カウンタ:0→1
  2. IInterface* b=a;
  3. b->AddRef(); // 参照カウンタ:1→2
  4. IInterface* c=a;
  5. c->AddRef(); // 参照カウンタ:2→3
  6. a->Release(); // 参照カウンタ:3→2
  7. b->Release(); // 参照カウンタ:2→1
  8. c->Release(); // 参照カウンタ:1→0(開放)
  9.  
のようにちょっと面倒です
そのため、簡単に扱えるようにある程度までは自動化できるクラスを作っておくと便利です
(便利なだけで、こんなクラスはなくても十分動きます)

ググればいっぱい出てきますけど、ここでは作ってみました

class com_ptr<C>

使えそうな関数は以下の通り
IsValid ポインタが有効か(NULLでないか)?
Attach ポインタを参照カウンタをあげずに設定する
Reset ポインタをNULLにする
使えそうな演算子は以下の通り
= 代入する(型違いのcom_ptr<C2>でもOK)
* 実体を得る
-> メンバ変数・関数を選択する
== ポインタが同じか(型違いのcom_ptr<C2>でもOK)
!= ポインタが違うか(型違いのcom_ptr<C2>でもOK)

前の例をこれを使ったっぽく書き直すと
  1. com_ptr<IInterface> a;
  2. a.Attach(CreateInterface()); // 参照カウンタ:0→1
  3. com_ptr<IInterface> b;
  4. b=a; // 参照カウンタ:1→2
  5. com_ptr<IInterface> c;
  6. c=a; // 参照カウンタ:2→3
  7. // Release関数はa,b,cのインスタンスのデストラクタ時に呼び出されるので勝手に開放される
  8. // マニュアルで開放したい場合はReset関数を使う
  9. a.Reset(); // 参照カウンタ:3→2
  10. b.Reset(); // 参照カウンタ:2→1
  11. c.Reset(); // 参照カウンタ:1→0
  12.  

最終更新:2009年06月20日 18:30
ツールボックス

下から選んでください:

新しいページを作成する
ヘルプ / FAQ もご覧ください。
添付ファイル