ボンジュール・マドモアゼル

本サイトの情報は自己責任にてご利用下さい。

[Inside COM] Inside COM 第8章 コンポーネントの再利用:包含と集約(その2)

 
外側のコンポーネントが非委譲unknownやそのほかの内側のコンポーネントに属するインターフェースを要求すると、外側のコンポーネントの参照カウントがインクリメントされている。これは、クライアントが内側のコンポーネントに属するインタフェースを要求したときは理想的な展開である。
Inside COM 163頁 8.3.5

下線部の "非委譲unknownや" の記述に問題がある。
NondelegatingQueryInterface の実装を確認すると、
HRESULT __stdcall CB::NondelegatingQueryInterface(const IID& iid,
                                                  void** ppv)
{     
    if (iid == IID_IUnknown)
    {
        // !!! CAST IS VERY IMPORTANT !!!
        *ppv = static_cast<INondelegatingUnknown*>(this) ;
    }
    else if (iid == IID_IY)
    {
        *ppv = static_cast<IY*>(this) ;
    }
    else
    {
        *ppv = NULL ;
        return E_NOINTERFACE ;
    }
    reinterpret_cast<IUnknown*>(*ppv)->AddRef() ;
    return S_OK ;
}
Inside COM 158-159頁 8.3.3

下から3行目の AddRef() の呼び出しで、委譲AddRef を呼び出し、外側のコンポーネントの参照カウントをインクリメントしているように見える。
しかし、reinterpret_cast<IUnknown*>(*ppv) のキャストに注目して欲しい。
IID_IUnknown が要求された場合、ppv は、 static_cast<INondelegatingUnknown*>(this) となり、AddRef() 呼び出しは、 reinterpret_cast によって、NondelegatingAddRef() が呼び出されるのではあるまいか。
したがって、「外側のコンポーネントが非委譲unknownやそのほかの内側のコンポーネントに属するインターフェースを要求すると」の非委譲unknown を要求した場合に限っては内側のコンポーネントの参照カウントがインクリメントされるのではないか。一方、要求されたインタフェースが非委譲unknown でなければ、IUnknown を継承しているはずなので、委譲AddRefが呼ばれるだろう。

ところで、クライアントが内側のインタフェースを要求するとき、なぜ、内側の参照カウントではなく外側の参照カウントがインクリメントされることが理想的なのか。
この理由は、内側のコンポーネントの生存期間は、外側のコンポーネントの生存期間に包括されるという寿命管理の要件にある。集約オブジェクトの寿命管理では、外側のコンポーネントがディアクティベートされたら、内側のコンポーネントもディアクティベートされるべきである。

もし、クライアントが、内側のコンポーネントの参照カウントを直接制御するAddRef、Release を呼び出すとしたらどうなるか。そうすると、外側のコンポーネントの関知しないところで、内側のコンポーネントの寿命管理が行われることになる。これではまずい。
したがって、外側のコンポーネントは、内側のコンポーネントについてAddRef、Release による参照/解除の通知を必要とする。
<<Inside COM 第8章 コンポーネントの再利用:包含と集約 | ホーム | ORACLE PL/SQL 結合配列 FOR ループ>>

コメント

コメントの投稿

管理者にだけ表示を許可する

画像の文字を半角数字で下記ボックスに記入ください。
文字が読みにくい場合はブラウザの更新をすると新しい文字列が表示されます。