gpt4 book ai didi

c++ - 如何在不必绑定(bind)到特定类的情况下实现观察者模式?

转载 作者:太空宇宙 更新时间:2023-11-04 13:07:00 24 4
gpt4 key购买 nike

我想观察一个对象在函数级别被删除。换句话说,我会说在一个函数内部,观察那个对象并允许我询问一些东西以了解它是否已被删除。函数完成后,不要再观察了。

这是我当前的 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 中。我可以具体说明类型,但我宁愿让编译器来确定它。所以我的问题是,有没有办法遍历继承树来找到对象?或者也许还有其他方法可以做到这一点?

我也宁愿不必向要观察的类添加额外的函数和成员。我已经想到了这一点,但如果我能有一个更清晰的分离,我会很高兴。

最佳答案

直到现在我还没有机会看到@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);
}

关于c++ - 如何在不必绑定(bind)到特定类的情况下实现观察者模式?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41752310/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com