参照カウントの実装

参照カウントには、クラスの実装者とそのクラスのオブジェクトを使用するクライアントの両方の側での作業が必要です。 クラスを実装するときは、IUnknown インターフェイスの一部として AddRef メソッドと Release メソッドを実装する必要があります。 これら 2 つのメソッドには、次のような簡単な実装があります。

  • AddRef は、オブジェクトの内部参照カウントをインクリメントします。
  • Release は、最初にオブジェクトの内部参照カウントをデクリメントしてから、参照カウントが 0 に減少したかどうかをチェックします。 0 の場合は、誰もオブジェクトを使用していないので、Release 関数はオブジェクトの割り当てを解除します。

ほとんどのオブジェクトの一般的な実装方法は、(QueryInterface と共に) これらのメソッドの実装を 1 つだけ持つことです。これは、すべてのインターフェイス間で共有されるため、オブジェクト全体に適用される参照カウントです。 ただし、クライアントの観点からは、参照カウントは厳密かつ明確にインターフェイス ポインターごとの概念であり、したがって、現在存在するインターフェイス ポインターに基づいて機能の一部を動的に構築、破棄、読み込み、またはアンロードすることによって、この機能を利用するオブジェクトが実装される可能性があります。 これらは、一般にティアオフ インターフェイスと呼ばれています。

新しいインターフェイス ポインターを返す QueryInterface などのメソッド (または API 関数) をクライアントが呼び出すたびに、呼び出されるメソッドは、返されたポインターを介して参照カウントをインクリメントします。 たとえば、クライアントが最初にオブジェクトを作成するとき、クライアントから見て参照カウントが 1 であるオブジェクトへのインターフェイス ポインターを受け取ります。 クライアントがインターフェイス ポインターで AddRef を呼び出すと、参照カウントは 2 になります。 クライアントは、オブジェクトへのすべての参照を削除するために、インターフェイス ポインターで Release を 2 回呼び出す必要があります。

参照カウントが厳密にインターフェイスごとのポインターである方法の例は、クライアントが新しいインターフェイスまたは同じインターフェイスの最初のポインターで、QueryInterface を呼び出したときに発生します。 いずれの場合も、クライアントはポインターごとに Release を 1 回呼び出す必要があります。 COM では、オブジェクトが同じインターフェイスを複数回要求された場合に同じポインターを返す必要はありません。 (これに対する唯一の例外は、COM に対するオブジェクトを識別する IUnknown です)。これにより、オブジェクトの実装でリソースを効率的に管理できます。

スレッド セーフは、AddRefRelease を実装する際の重要な問題でもあります。 詳細については、「プロセス、スレッド、およびアパートメント」を参照してください。

参照カウントによるオブジェクトの有効期間の管理