我想观察在功能级别删除的对象。换句话说,我会说在一个函数内部,观察该对象并允许我询问一些事情,以确定它是否已被删除。完成此功能后,请不要再观察它了。
这是我目前的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));
}
要使用,析构函数中会调用MarkDeleted()
并传递this
。然后在函数中,它将使用DeleteReporter
实例化make_DeleteReporter()
传递对象进行观察。稍后,将查询DeleteReporter
对象以确保在实例化之后某个时间没有删除该对象,然后再尝试与之对话。
最初,我没有将其作为模板,而是功能已经void*
。然后我意识到,如果对象是多次继承的,则指针可能无法正确匹配。
如我所做的那样使用模板实现也会导致这种情况发生,因为指针可能在错误的vector
中。我可以明确说明类型,但我宁愿让编译器确定这个。所以我的问题是,有没有办法遍历继承树来找到对象?或者也许还有其他方法可以做到这一点?
我也不想在类中添加额外的函数和成员来观察。我已经想到了这一点,但是如果我能有一个更清晰的分离,我希望如此。
答案 0 :(得分:0)
我没有机会看到@Igor给出的评论,但是昨晚我正在考虑这个问题,我认为无法确定正确的清单,所以我和#39;我没有打扰并声明用户必须知道要注意的类型。
我也想到了与@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);
}