« DLL内の関数 | メイン | アロケーターの集成化 »

2004年09月04日

吉里吉里2/KAG3ムービー拡張日誌:: 終了時アクセス違反の調査

    

IGraphBuilderを最後にリリースしているのだが、どうやらこの部分でアクセス違反が起きているらしい。
なぜか、すでにリリースされてしまっているようだ。

集成の問題か!
もらったー!
やはり、集成の問題だった。
CBaseVideoRendererを継承したレンダーのコンストラクタで、CBaseControlVideoを継承したクラスをメンバに持っているので、CBaseControlVideo::CBaseControlVideo( NAME("Video properties"), pUnk, phr, &m_InterfaceLock, this ) と言うように初期化していた。
しかし、本来はCBaseControlVideo::CBaseControlVideo( NAME("Video properties"), GetOwner(), phr, &m_InterfaceLock, this ) と初期化しなければならない。
コンストラクタで渡されるpUnkは集成された所有者オブジェクトへのポインタと説明されている。
そして、pUnkがどこから渡されるかと言えばクラスファクトリだ。
さらに追うと利用者がCoCreateInstanceから渡たすものだ。
で、CoCreateInstanceではNULLと指定していた。集成なしということだ。
つまり、最初のように初期化すると集成なしとされる。
これがどういうことになるかというと、リリースした時メンバ変数をdeleteしようとしてしまう。
ま、おかしくなって当然ですな。
そして、本来は2番目の初期化方法のようにGetOwner()によって、集成もとのオブジェクトのポインタを得るわけだ。
そうすれば、参照カウンタは集成元のオブジェクトのものが使われるようになり、解放時もオーナーが解放されるようになる。
これで、万事O.K.と言うわけだ。


集成の説明 (間違っているかも)
複数のインターフェイスを1つのクラスに持たせる場合、多重継承が使われるが、多重継承を使いたくない場合というのは往々にしてある。
そんなとき、よくメンバにそのクラスを持ってしまうと言う方法がとられる。
そして、そのクラスが保持するインターフェイスが要求された時、そのメンバのポインタを返すことで要求を満たす。
これが集成である。
しかし、COMの場合、すべてのインターフェイスは参照カウンタを保持する。そして、参照カウンタが0になった時、そのオブジェクトはdeleteされる。
つまり、メンバ変数がdeleteされるという状況に遭遇してしまう。
このような状況を回避するため、集成されたオブジェクトはそのオブジェクトをメンバとして保持しているオブジェクトのポインタを保持し、参照カウンタへの操作は、その保持しているオブジェクトのものをコールされる。
つまり、集成する場合は、以上のようなルールに従わなければならない。
そして、このようなものを集成と言う。

以上のような形体以外の実装も存在するようだが、だいたい集成とはこんな感じです。



投稿者 Takenori : 2004年09月04日 02:06




comments powered by Disqus
Total : Today : Yesterday : なかのひと