1 つの方法は、関数の戻り値を使用しないことです。2番目のケースのように、出力パラメーターのみを使用してください。とにかく、これは公開された COM インターフェイスではすでにルールになっています。
これは「公式」リファレンスですが、典型的なように、最初のケースについても言及していません: http://support.microsoft.com/kb/104138
しかし、コンポーネント内で戻り値を禁止すると、見苦しいコードになります。構成可能性があると、はるかに優れています。つまり、関数を便利にまとめて、ある関数の戻り値を引数として直接別の関数に渡します。
スマート ポインターを使用すると、それが可能になります。これらはパブリック COM インターフェイスでは禁止されていますが、HRESULT 以外の戻り値も禁止されています。その結果、あなたの問題はなくなります。戻り値を使用してインターフェイス ポインターを返す場合は、スマート ポインターを介して行います。また、スマート ポインターにもメンバーを格納します。
ただし、何らかの理由でスマート ポインターを使用したくない場合 (ちなみに、あなたは気が狂っています!)、あなたの推論は正しいと言えます。あなたの関数は「プロパティゲッター」として機能していますが、最初の例ではそうすべきではありませんAddRef
。
したがって、あなたのルールは正しいです (ただし、実装にはバグがありますが、発見していない可能性があるため、すぐにわかります)。
この関数はオブジェクトを必要とします:
void Foo(IUnknown *obj);
obj
メンバー変数に格納する場合を除き、 の refcountに影響を与える必要はまったくありません。それが戻る前に呼び出すことは、確かにFooの責任であってはなりません! 作成される混乱を想像してください。Release
obj
この関数はオブジェクトを返します。
IUnknown *Bar();
そして、ある関数の出力を別の関数に直接渡すことで、関数を構成することがよくあります。
Foo(Bar());
Bar
返されたものの参照カウントを増やしていた場合、これは機能しません。誰が行くのRelease
?を呼び出しBar
ませんAddRef
。これは、保存および管理するものを返すことを意味します。つまり、実質的にプロパティ ゲッターです。
また、呼び出し元がスマート ポインターを使用している場合は、次のようになりp
ます。
p = Bar();
AddRef
オブジェクトが割り当てられると、正常なスマート ポインターが移動します。もしもうまくやっBar
ていたらAddRef
、また1カウント漏らしてしまいました。これは実際には、同じ構成可能性の問題の特殊なケースにすぎません。
出力パラメーター (ポインターからポインター) は、構成可能性の問題の影響を同じように受けないため、異なります。
繰り返しますが、スマート ポインターは、2 番目の例を使用して、最も一般的なケースを提供します。
myClass.getObj(&p);
スマート ポインターは、ここでは参照カウントgetObj
を実行しないため、実行する必要があります。
今、私たちはバグに来ます。スマート ポインターp
が何かに渡されたときに既に何かを指しているとしgetObj
ます。
修正版は次のとおりです。
void getObj(IUnknown **outObj)
{
if (*outObj != 0)
(*outObj)->Release();
*outObj = m_obj;
(*outObj)->AddRef(); // might want to check for 0 here also
}
operator&
実際には、人々はその間違いを頻繁に犯すので、スマート ポインターが既にオブジェクトを持っているときに呼び出された場合にアサートする方が簡単だと思います。