注意してください - これらのビルドは VS2008/VS2010 ビルド用で、11 のコンストラクトは使用できません。
ある出版社の話を聞いている購読者がいると想像してください。パブリッシャーには、サブスクライバー ポインターのコンテナーがあります。私の void detach(ISubscriber *) では、サブスクライバー リストをロックする代わりに、そのサブスクライバーの適切な単語がないため、ポインターを "NULL" します。
//My container in the publisher. Inserts to not invalidate, removals only invalidate iterators pointing to the removed element, for this reason we NULL
Container<ISubscriber *> myContainer;
Now in the publisher...
void NotifySubscribers(){
foreach(subscriber in container){
if(subscriber)//This is my problem
subscriber->notify()
}
}
3 行目 - ポインターがテストされ、有効なオブジェクトを指しています。行 4 が実行される前に、別のスレッドがサブスクライバーを NULL にします。ライン 4 - ブーム。
私の質問は、テストと呼び出しがアトミックになるように、ある種のインターロックされたものを使用できる方法はありますか。
たとえば、デストラクタで参照カウントされたオブジェクトの場合、次のようなものが機能します
RefCountObject::~RefCountObject(){
if(InterlockedDecrement(&m_count) == 0)
delete m_data;
}
ここでは、参照カウンターがデクリメントされ、自動的にゼロに対してテストされ、ゼロに等しい場合にのみ、データが解放されます。
ポインターの有効性に基づいて関数を呼び出すためにこれを行う方法はありますか?
編集 1: コメントに基づいて少し明確にする必要があります。返信ありがとうございます。パブリッシャーは、サブスクライバーの "メモリの解放" に対して責任を負わないため、リークは発生しません。通知の後、パブリッシャーは、null アウトされたサブスクライバーを削除してコンテナーをクリーンアップするループを通過します。
次に、加入者自身についてです。彼らが切り離すとき、彼らは出版社の話を聞くことから切り離されているだけです。それら自体は静的オブジェクトで存続します (これは私たちが必要としているコントラクトです)。なんで?通知中にロックを保持する余裕がないためです。他の唯一のオプションは、将来のバージョン管理のために、この DLL に組み込まれないことが決定された Share_Ptr を使用することでした。
私は手書きの shared_ptr を作成しましたが、リソース管理クラスにラップされていないオブジェクトへの参照は同じ落とし穴に陥り、サブスクライバーがそうしないことを確認する必要がある「要件」をプッシュするだけであることに気付きました。上記のサブスクライバーの実装内のダングリング参照を参照してください。
サブスクライバーを「解放」することはできません。現在、これを使用するすべてのクライアントは静的オブジェクトです。私たちはただ未来を見据えていました。一部のユーザーはレガシー アプリであり、enabled_shared_from_this などを取り込むのは容易ではありません。