4

オブジェクトを返すメソッドを持つ COM インターフェイスがあります。

interface ICreatorInterface {
    HRESULT CreateObject( IObjectToCreate** );
};

重要なのは、呼び出しがインターフェイスICreatorInterface::CreateObject()を実装するオブジェクトを取得する唯一の方法であるということです。IObjectToCreate

C++ では、次のようにできます。

 HRESULT CCreatorInterfaceImpl::CreateObject( IObjectToCreate** result )
 {
     //CObjectToCreateImpl constructor sets reference count to 0
     CObjectToCreateImpl* newObject = new CObjectToCreateImpl();
     HRESULT hr = newObject->QueryInterface( __uuidof(IObjectToCreate), (void**)result );
     if( FAILED(hr) ) {
         delete newObject;
     }
     return hr;
 }

またはこの方法

 HRESULT CCreatorInterfaceImpl::CreateObject( IObjectToCreate** result )
 {
     //CObjectToCreateImpl constructor sets reference count to 1
     CObjectToCreateImpl* newObject = new CObjectToCreateImpl();
     HRESULT hr = newObject->QueryInterface( __uuidof(IObjectToCreate), (void**)result );
     // if QI() failed reference count is still 1 so this will delete the object
     newObject->Release();
     return hr;
 }

違いは、参照カウンターの初期化方法と、QueryInterface()失敗した場合のオブジェクト削除の実装方法です。CCreatorInterfaceImpl私は両方を完全にコントロールしているのでCObjectToCreateImpl、どちらの方法でも行くことができます。

IMO 最初のバリアントはより明確です。すべての参照カウントは 1 つのコードに含まれています。私は何かを監督しましたか?なぜ 2 番目のアプローチの方が優れているのでしょうか。上記のどれがより良いですか、そしてその理由は何ですか?

4

3 に答える 3

3

どちらのバリエーションも、COM の非常に基本的な原則に違反しています。

  • 参照カウントが 0 の COM オブジェクトに対して、AddRef 以外のメソッドを呼び出さないでください。

そうしないと、あらゆる種類のエラーが発生します。簡単に言えば、オブジェクトに対して完全に合法的な操作を行うことができなくなるためです。それらをスマートポインターに入れるようなものです。スマート ポインターは AddRef を呼び出し、カウントを 1 に設定し、その後リリースしてカウントを 0 に設定し、オブジェクトを自己破壊させます。

はい、QueryInterface の実装の 90% がこれを行っていないことを認識しています。しかし、私はまた、そうする人がいることを保証します:)

最も簡単な方法は、オブジェクトを作成した直後に AddRef を呼び出すことだと思います。これにより、オブジェクトは可能な限り早い段階で通常の COM オブジェクトのように動作できます。

私は過去にこの問題に遭遇したことがあり、(オブジェクトが ATL で実装されていると仮定して) ちょっといいヘルパー メソッドを書きました。

template <class T>
static 
HRESULT CreateWithRef(T** ppObject)
{
    CComObject<T> *pObject;
    HRESULT hr = CComObject<T>::CreateInstance(&pObject);
    if ( SUCCEEDED(hr) )
    {
        pObject->AddRef();
        *ppObject = pObject;
    }

    return hr; 
}
于 2010-01-15T07:56:24.863 に答える
2

Raymond Chen が彼のウェブログに関連記事を書きました: 参照カウントがゼロのオブジェクトについて

于 2010-01-15T09:07:57.433 に答える
0

メモリの問題を回避するために、返される com オブジェクトを作成するために常に次のコード シナリオを使用します。もちろん、私のオブジェクトは作成時に参照カウント= 0であるため、これは機能します。これは、削除演算子を使用してエラー状態を処理しようとするよりも常に明確に思えます。

 HRESULT CCreatorInterfaceImpl::CreateObject( IObjectToCreate** result )
 {
     //CObjectToCreateImpl constructor sets reference count to 0
     CObjectToCreateImpl* newObject = new CObjectToCreateImpl();

     newObject->AddRef();

     HRESULT hr = newObject->QueryInterface( __uuidof(IObjectToCreate), (void**)result);

     newObject->Release(); // release my addref, if QI succeeded it AddRef'd, if not the object is destroyed

     return hr; // return result from QI
 }
于 2010-01-15T14:06:42.890 に答える