我想观察一个在功能级别被删除的对象。换句话说,我将在函数内部说,观察该对象,然后让我询问某些东西以了解它是否已被删除。功能完成后,不再观察。

这是我当前的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/

10-11 22:13
查看更多