機能レベルで削除されているオブジェクトを監視したいと考えています。言い換えれば、私は関数の中でそのオブジェクトを観察し、削除されたかどうかを知るために何かを調べることができるようにします。機能が終了したら、もう観察しないでください。特定のクラスにバインドせずにオブザーバパターンを実装する方法は?
これは私の現在のAPIです:
template <typename T>
class DeleteReporter
{
std::pair<T*, bool>* obj_deleted_pair;
public:
DeleteReporter(T* pObject);
operator bool();
~DeleteReporter();
};
template <typename T>
DeleteReporter<T> make_DeleteReporter(T* pObject);
template <typename T>
void MarkDeleted(T* pObject);
そして、ここでは実装です:
template <typename T>
std::vector<std::pair<T*, bool>>& obj_deleted_pairs()
{
static std::vector<std::pair<T*, bool>> obj_deleted_pairs;
return obj_deleted_pairs;
}
template <typename T>
DeleteReporter<T> make_DeleteReporter(T* pObject)
{
return DeleteReporter<T>(pObject);
}
template <typename T>
void MarkDeleted(T* pObject)
{
auto it = std::find_if(obj_deleted_pairs<T>().begin(), obj_deleted_pairs<T>().end()
, [pObject](std::pair<T*, bool>& obj_deleted_pair)
{
return obj_deleted_pair.first == pObject;
});
if (it != obj_deleted_pairs<T>().end())
{
it->second = true;
}
}
template <typename T>
DeleteReporter::DeleteReporter(T* pObject)
{
obj_deleted_pairs<T>().emplace_back(pObject, false);
obj_deleted_pair = &*obj_deleted_pairs<T>().rbegin();
}
template <typename T>
DeleteReporter::operator bool()
{
return obj_deleted_pair->second;
}
template <typename T>
DeleteReporter::~DeleteReporter()
{
obj_deleted_pairs<T>().erase(obj_deleted_pairs<T>().begin()
+ std::distance(&*obj_deleted_pairs<T>().begin(), obj_deleted_pair));
}
使用するには、それに渡されたthis
とMarkDeleted()
にデストラクタでの呼び出しがあるだろう。関数内では、make_DeleteReporter()
を使用してオブジェクトを渡して、DeleteReporter
をインスタンス化します。その後、DeleteReporter
オブジェクトは、インスタンス化後にオブジェクトが削除しようとする前に削除されないように照会されます。
元々、これはテンプレートとして用意されていませんでしたが、代わりに関数はvoid*
となりました。オブジェクトが複数継承されていると、ポインタが正しく一致しない可能性があります。
私が行ったようにテンプレートを使って実装すると、ポインタが間違っている可能性があります(vector
)。私は具体的に型を述べることができますが、私はむしろコンパイラにこれを決定させるでしょう。だから私の質問は、オブジェクトを見つけるために継承ツリーを横断するいくつかの方法はありますか?あるいは、これができる他の方法がありますか?
私はまた、観察するクラスに追加の関数やメンバーを追加する必要はありません。私はそれを考えましたが、もし私がより洗練された分離をすることができればそれを望みます。
'obj_deleted_pair =&* obj_deleted_pairs().rbegin();'危険、ウィル・ロビンソン!ベクトルに追加すると、すべてのポインタ、参照、イテレータがベクトルの既存の要素に無効になることがあります。 'DeleteReporter'の新しいインスタンスを作成すると、他のすべての静止しているインスタンスに、ぶら下がっているポインタが残ることがあります。 –
また、オブジェクトが作成され、破棄された後、別のオブジェクトが同じアドレスで作成され、最終的に破棄される可能性があります。この場合、ベクトル上に同じポインタを持つ2つのペアがありますが、 'MarkDeleted'は最初のものを2回更新します。 –
ベクトルから消去すると( '〜DeleteReporter'のように)、消去された要素とそれに続くすべての要素に対するすべてのポインタ参照とイテレータも無効になります。 –