3

インターフェイスを実装するときCOM、成功時には常に out パラメータに割り当てますが、エラー時にも割り当てる必要がありますか?

HRESULT CDemo::Div(/*[in]*/ LONG a, /*[in]*/LONG b, /*[out,retval]*/ LONG* pRet)
{
    if (pRet == NULL)
        return E_POINTER;

    if (b == 0)
    {
        *pRet = 0; // is this redundant?
        return E_INVALIDARG;
    }

    *pRet = a/b;
    return S_OK;
}

かつて、out パラメーターを初期化せず、変数を初期化した場合、メソッド内で変更しなければその値のままであると仮定して、鼻を噛まれました。ただし.NET、マーシャラーはこれが[out]パラメーターであることを認識しているため、呼び出しサイトに配置した初期値を破棄し、関数が返された後にガベージに入れました (それをデバッグするのは楽しかったです)。

障害過補償でもパラメーターに割り当ててoutいますか、それとも本当に行うべきですか?


編集:関数が失敗した場合、正式にはパラメータにアクセスするべきではありませんが、私はしばしば次のようなコードを目にします(そして時々書く)( sharptoothの投稿の例を使用):

ISmth *pSmth = NULL; 
pObj->GetSmth(&pSmth); // HRES is ignored
if (pSmth) // Assumes that if GetSmth failed then pSmth is still NULL
{ 
    pSmth->Foo();
    pSmth->Release();
}  

これは、マーシャリングされていないコード (同じスレッド アパートメント) では正常に機能しますが、マーシャラーが関与している場合、関数が成功した場合にのみ戻り値を設定するのに十分スマートですか?

4

3 に答える 3

3

他の回答は間違っていませんが、非常に重要な点を見落としています。失敗を返すつもりの COM サーバーは、HRESULT ですべての [out] パラメータを NULL に設定する必要がありますこれは単なるスタイルの良さの問題ではなく、COM で必要とされており、マーシャリングが関係している場合にこれに従わないと、ランダムなクラッシュが発生する可能性があります。

つまり、*pRet = 0; 元のコードでは冗長ではありませんが、正しくて必要です。

于 2009-05-04T19:36:34.190 に答える
3

ルールは、呼び出しが失敗した場合、呼び出し側が out パラメータ値を使用して何もすることを許可しないというものです。したがって、サーバーは有効な値を提供してはならず、リソースの所有権を out パラメータに渡してはなりません。

たとえば、

HRESULT GetSmth( [out] ISmth** );

AddRef()メソッドの場合、サーバーがISmth**変数を返す前に呼び出すことが期待されます。クライアントは返された out パラメーター値を使用することが許可されていないため、呼び出しを行わず、メモリ リークが発生するAddRef()ため、失敗コードを返す場合は呼び出してはなりません。Release()

于 2009-04-01T11:45:55.457 に答える
1

シャープトゥースに100%同意するかどうかはわかりません。COM呼び出しが失敗した場合、outパラメーターにリソースの所有権を割り当てることはできません。これには、メモリ割り当てまたはCOMオブジェクトのAddRefが含まれます。

ただし、リソースの所有権が譲渡されない限り、パラメーターを空の値に設定することには何の問題もありません(実際には推奨されます)。たとえば、コードがpRetを0に設定することについて技術的に違法なことは何もありません。これは、リソースの所有権をpRetに譲渡せず、呼び出しの成功を適切にチェックしなかった一部の呼び出し元の単なるヘルパーです。

于 2009-04-01T13:20:26.463 に答える