기능 수준에서 삭제되는 개체를 관찰하고 싶습니다. 다시 말해, 함수의 내부에서 그 객체를 관찰하고 내가 삭제되었는지 여부를 알기 위해 무언가를 조사하도록 허용합니다. 기능이 완료되면 더 이상 관찰하지 마십시오.특정 클래스에 바인딩하지 않고 관찰자 패턴을 구현하는 방법은 무엇입니까?
이 내 현재의 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()
에 소멸자의 호출이있을 것입니다. 그런 다음 함수에서 DeleteReporter
을 인스턴스화하여 make_DeleteReporter()
을 사용하여 관찰 할 객체를 전달합니다. 나중에 DeleteReporter
개체를 쿼리하여 개체가 인스턴스화 후에 언젠가 삭제되지 않도록 보장합니다.
원래 템플릿으로 사용하지는 않았지만 그 대신 함수는 void*
을 사용했습니다. 그런 다음 개체가 여러 번 상속 된 경우 포인터가 제대로 일치하지 않을 수도 있음을 알았습니다.
필자가 한 것처럼 템플릿을 사용하여 구현하면 포인터가 잘못된 vector
에있을 수도 있습니다. 구체적으로 타입을 명시 할 수는 있지만, 컴파일러가이를 결정하게합니다. 그래서 내 질문은 객체를 찾기 위해 상속 트리를 가로 지르는 방법이 있을까요? 아니면 다른 방법으로이 작업을 수행 할 수 있습니까?
나는 또한 관찰 할 클래스에 추가 기능과 멤버를 추가 할 필요가 없다. 나는 그것의 생각을 가지고 있지만, 내가 더 깨끗한 분리를 할 수 있다면 그것을 원할 것이다.
'obj_deleted_pair = * obj_deleted_pairs() .rbegin();'위험, 윌 로빈슨! 벡터에 추가하면 모든 포인터, 참조 및 반복기가 벡터의 기존 요소로 무효화 될 수 있습니다. 'DeleteReporter'의 새로운 인스턴스를 생성하면 다른 모든 살아있는 인스턴스는 매달려있는 포인터를 가질 수 있습니다. –
또한 개체가 만들어지고 파괴 된 다음 다른 개체가 동일한 주소로 만들어지고 (결국 파괴 될 수도 있음) 가능할 수 있습니다. 이 경우, 벡터에 같은 포인터를 가진 두 쌍을 갖게되지만,'MarkDeleted'는 첫 번째 것을 두 번 업데이트합니다. –
벡터에서 지우기 ('~ DeleteReporter'는)는 지워진 요소와 그 뒤의 모든 요소에 대한 모든 포인터 참조 및 반복자를 무효화합니다. –