議論を明確にするために、問題を非常に一般的な方法で説明します。つまり、実際のクラスの名前を提供したり、ドメイン/コンテキストを説明したりしません (ただし、そうであることが判明した場合は、急)。
クラスを想像してみてくださいA
。このクラスに 2 つの不変フィールドを持たx
せy
ます。さらに、これらとをプライマリフィールドにします。つまり、 /演算子とハッシュ計算関数の実装でのみ使用されます。x
y
==
!=
A
はandに関して不変であるため、 (たとえばand )の複数のインスタンス(つまり、)がそれらのandへのアクセスを暗黙的に共有できるようにすることで、不要な重複がないようにします。x
y
A
a1
a2
a1.x == a2.x
a1.y == a2.y
a1 == a2
x
y
A
さらに、 :に別のフィールドがあると想像してくださいz
。これは、セカンダリで可変であり、 の一種の動作調整として機能しますA
。設計上、このフィールドをtooの等しいインスタンス間で共有することが望まれます。したがって、この変更を呼び出すと、へのアクセスが共有されているため、影響も受けます。A
a1.setZ(...)
a2
z
その結果、A
純粋な値セマンティクスを持つクラスになりますが、そのメンバーは等しいインスタンス間で暗黙的に共有されます。私の知る限り、そのようなパターンはFlyweightまたはaliasingと呼ばれます。
質問に移る前に、もう 1 つ詳細を説明します。プロジェクトのほとんどのクラスは、Pimplイディオムを使用して実装されています。
private:
class Private;
Private* p;
クラスA
は除外ではありません。そのため、上記のスキームを実装するための提案されたアイデアは次のとおりです。
- Pimplのイディオムでは、生のポインターではなく、
共有ポインターを使用します。
A::Private
- への共有ポインタのグローバル セットを持ってい
A::Private
ます。 - のコンストラクターで、適切な共有ポインターがセットに既に存在する
A
かどうかを確認し(利用して、もちろん)、存在する場合は単にそれに設定 し、そうでない場合は新しいインスタンスを作成してこのセットに共有ポインターを格納 し、同様にそれに設定します。A::Private
x
y
p
A::Private
p
A::Private
のデストラクタは、共有ポインタをthis
セットから削除する必要があります。
これは、最も簡単で直感的な実装のように見えます。ただし、問題は、このグローバル セットが への共有ポインタを保持しているためA::Private
、対応する のすべてのインスタンスA
が破棄された場合でも、参照カウンタが に留まり、1
に達することがなく0
、したがってメモリが解放されないことです。
いくつかの共有ポインターが参照カウンターの下限を設定する方法を提供すると良いと思いました。この場合、たとえば、1
到達1
するとメモリが解放されるように設定するだけです。残念ながら、一般的なライブラリ (Boost、Qt、Poco など) でそのような動作の実装を見つけられませんでした。もちろん、自分の問題に対して手動で参照カウントを行うこともできますが、それは適切ではなく、車輪の再発明のようなにおいがします。
おそらく、この問題を解決する他の方法があります。あなたの提案を楽しみにしています。
注:この問題を私がよく知っているポインター セマンティクスに変換するようにというアドバイスがあれば、すぐに傍受したいと思います。上記のスキームに正確に対応するソリューションが必要です。