1

AddRef を実行するかどうかに基づいて参照カウントされたオブジェクトを返す関数のシグネチャには、常に次の規則を使用してきましたが、同僚にも説明したいと思います...だから私の質問は、以下に説明する規則です広く守られているルール?このスタイルを提唱する (たとえば) コーディング規則へのポインターを探しています。


関数がオブジェクトへの参照を追加しない場合は、関数の戻り値として返される必要があります。

class MyClass
{
protected:
    IUnknown *getObj() { return m_obj; }
private:
    IUnknown *m_obj;
};

ただし、関数がオブジェクトへの参照を追加する場合、オブジェクトのポインタからポインタへのポインタがパラメータとして関数に渡されます。

class MyClass
{
public:
    void getObj(IUnknown **outObj) { *outObj = m_obj; (*outObj)->AddRef(); }
private:
    IUnknown *m_obj;
};
4

3 に答える 3

2

多くの COM を使用するプロジェクトで、これと同じスタイルを使用しました。それは、NuMega で SoftICE と呼ばれるちょっとしたものに取り組んでいたときにそれを学んだ 2 人の人々から教えられました。これは、Don Box の著書「Essential COM」で教えられているスタイルでもあると思います (こちらは Amazon にあります)。一時期、この本は COM のバイブルと見なされていました。そうでない唯一の理由は、COM が単なる COM ではなくなったからだと思います。

とはいえ、私は CComPtr やその他のスマート ポインターを好みます。

于 2009-02-11T11:40:11.833 に答える
2

1 つの方法は、関数の戻り値を使用しないことです。2番目のケースのように、出力パラメーターのみを使用してください。とにかく、これは公開された COM インターフェイスではすでにルールになっています。

これは「公式」リファレンスですが、典​​型的なように、最初のケースについても言及していません: http://support.microsoft.com/kb/104138

しかし、コンポーネント内で戻り値を禁止すると、見苦しいコードになります。構成可能性があると、はるかに優れています。つまり、関数を便利にまとめて、ある関数の戻り値を引数として直接別の関数に渡します。

スマート ポインターを使用すると、それが可能になります。これらはパブリック COM インターフェイスでは禁止されていますが、HRESULT 以外の戻り値も禁止されています。その結果、あなたの問題はなくなります。戻り値を使用してインターフェイス ポインターを返す場合は、スマート ポインターを介して行います。また、スマート ポインターにもメンバーを格納します。

ただし、何らかの理由でスマート ポインターを使用したくない場合 (ちなみに、あなたは気が狂っています!)、あなたの推論は正しいと言えます。あなたの関数は「プロパティゲッター」として機能していますが、最初の例ではそうすべきではありませんAddRef

したがって、あなたのルールは正しいです (ただし、実装にはバグがありますが、発見していない可能性があるため、すぐにわかります)。

この関数はオブジェクトを必要とします:

void Foo(IUnknown *obj);

objメンバー変数に格納する場合を除き、 の refcountに影響を与える必要はまったくありません。それが戻る前に呼び出すことは、確かにFooの責任であってはなりません! 作成される混乱を想像してください。Releaseobj

この関数はオブジェクトを返します。

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&実際には、人々はその間違いを頻繁に犯すので、スマート ポインターが既にオブジェクトを持っているときに呼び出された場合にアサートする方が簡単だと思います。

于 2009-02-11T11:42:27.397 に答える
2

新しいオブジェクトが作成され、呼び出し元がその所有権を取得する必要がある場合には、参照カウント スマート ポインターを使用する方がはるかに一般的です。

于 2009-02-11T10:59:34.537 に答える