2017-01-19 10 views
1

機能レベルで削除されているオブジェクトを監視したいと考えています。言い換えれば、私は関数の中でそのオブジェクトを観察し、削除されたかどうかを知るために何かを調べることができるようにします。機能が終了したら、もう観察しないでください。特定のクラスにバインドせずにオブザーバパターンを実装する方法は?

これは私の現在の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)); 
} 

使用するには、それに渡されたthisMarkDeleted()にデストラクタでの呼び出しがあるだろう。関数内では、make_DeleteReporter()を使用してオブジェクトを渡して、DeleteReporterをインスタンス化します。その後、DeleteReporterオブジェクトは、インスタンス化後にオブジェクトが削除しようとする前に削除されないように照会されます。

元々、これはテンプレートとして用意されていませんでしたが、代わりに関数はvoid*となりました。オブジェクトが複数継承されていると、ポインタが正しく一致しない可能性があります。

私が行ったようにテンプレートを使って実装すると、ポインタが間違っている可能性があります(vector)。私は具体的に型を述べることができますが、私はむしろコンパイラにこれを決定させるでしょう。だから私の質問は、オブジェクトを見つけるために継承ツリーを横断するいくつかの方法はありますか?あるいは、これができる他の方法がありますか?

私はまた、観察するクラスに追加の関数やメンバーを追加する必要はありません。私はそれを考えましたが、もし私がより洗練された分離をすることができればそれを望みます。

+0

'obj_deleted_pa​​ir =&* obj_deleted_pa​​irs ().rbegin();'危険、ウィル・ロビンソン!ベクトルに追加すると、すべてのポインタ、参照、イテレータがベクトルの既存の要素に無効になることがあります。 'DeleteReporter'の新しいインスタンスを作成すると、他のすべての静止しているインスタンスに、ぶら下がっているポインタが残ることがあります。 –

+0

また、オブジェクトが作成され、破棄された後、別のオブジェクトが同じアドレスで作成され、最終的に破棄される可能性があります。この場合、ベクトル上に同じポインタを持つ2つのペアがありますが、 'MarkDeleted'は最初のものを2回更新します。 –

+0

ベクトルから消去すると( '〜DeleteReporter'のように)、消去された要素とそれに続くすべての要素に対するすべてのポインタ参照とイテレータも無効になります。 –

答えて

0

@Igorが今までに与えたコメントは見られませんでしたが、昨夜はこれについて考えていましたが、正しいリストを決定することができないと判断したので、私はそうではありませんユーザーがどんな種類の時計を見るべきか知っていなければならないと迷惑を掛けている。

@Igorが指定したのと同じエラーが考えられました。ここで私が使用しています最終的な実装は次のとおりです。

#pragma once 
#include <memory> 
#include <vector> 
#include <algorithm> 

#define _AFXDLL // required if using the MFC DLL and not a static implementation 
#include <afx.h> // used for the ASSERT() macro 
// DeleteReporter 
// 
// DESCRIPTION 
// This class is to warn a function that at somepoint in its execution, the 
// object of interest has been deleted. 
// 
// USAGE 
// To use, add the function call MarkDeleted(this); to the end of the 
// destructor of the type you wish to test for. 
// 
// In the function that you want to check for the destruction, create a 
// DeleteReporter<T> variable, where T is the type where you added the 
// MarkDeleted(this) to. 
// 
// You can now query the object you created to determine if the object of 
// interest has been deleted. 
// 
// Example: 
// 
// C::~C() 
// { 
//  ... 
// 
//  MarkDeleted(this); 
// } 
// 
// void C::fn() 
// { 
//  ... 
// 
//  DeleteReporter<C> C_Deleted(this); 
// 
//  ... do stuff ... 
// 
//  if (!C_Deleted) 
//  { 
//  ... call member functions ... 
//  } 
// 
//  ... 
// } 
// 
//           By: Adrian Hawryluk January 2017 
template <typename T> 
void MarkDeleted(T* pObject); 

template <typename T> 
class DeleteReporter 
{ 
    friend void MarkDeleted<T>(T* pObject); 
    using  pair_t = std::pair<T*, bool>; 
    using shared_pair_t = std::shared_ptr<pair_t>; 
    struct vector_t; 

    static vector_t obj_deleted_pairs; 

    shared_pair_t obj_deleted_pair; 
public: 
    DeleteReporter(T* pObject); 
    DeleteReporter(DeleteReporter const &) = delete; 
    DeleteReporter(DeleteReporter  &&) = delete; 
    operator bool(); 
    ~DeleteReporter(); 
}; 




////////////////////////////////////////////////////////////////////////////// 
// Implementation 

template <typename T> 
void MarkDeleted(T* pObject) 
{ 
    using  vector_t = typename DeleteReporter<T>::vector_t; 
    using shared_pair_t = typename DeleteReporter<T>::shared_pair_t; 
    vector_t& obj_deleted_pairs = DeleteReporter<T>::obj_deleted_pairs; 
    for (shared_pair_t& obj_deleted_pair : obj_deleted_pairs) 
    { 
     if (obj_deleted_pair->first == pObject) 
     { 
      obj_deleted_pair->second = true; 
     } 
    } 
} 

template <typename T> 
struct DeleteReporter<T>::vector_t : std::vector<shared_pair_t> 
{ 
    ~vector_t() 
    { 
     // When deleting the storage vector, it should be empty, or there's an error 
     ASSERT(size() == 0); 
    } 
}; 

template <typename T> 
typename DeleteReporter<T>::vector_t DeleteReporter<T>::obj_deleted_pairs; 

template <typename T> 
DeleteReporter<T>::DeleteReporter(T* pObject) 
{ 
    obj_deleted_pair = std::make_shared<pair_t>(pObject, false); 
    obj_deleted_pairs.emplace_back(obj_deleted_pair); 
} 

template <typename T> 
DeleteReporter<T>::operator bool() 
{ 
    return obj_deleted_pair->second; 
} 

template <typename T> 
DeleteReporter<T>::~DeleteReporter() 
{ 
    auto& it = std::find(obj_deleted_pairs.begin(), obj_deleted_pairs.end(), obj_deleted_pair); 
    obj_deleted_pairs.erase(it); 
} 
関連する問題