如何确保给定的资源总是首先被删除

How to enforce that a given resource will always be removed first?

本文关键字:资源 删除 何确保 确保      更新时间:2023-10-16

在我的项目中,我有一个事件系统。你可以将一个回调函数连接到一个事件,任何时候事件被发送,你的回调函数就会被调用。

在连接到事件时,您将获得一个令牌。只要令牌没有被破坏,连接就处于活动状态:

class A
{
    A()
    {
        event_connection = get_dispatcher().connect(event, std::bind(member_function, this));
    }
    void member_function()
    {
        dummy_instance++; //any action that uses this field
    }
    // changed from shared to unique to avoid confusion
    //std::shared_ptr<event_connection_token> event_connection;
    std::unique_ptr<event_connection_token> event_connection;
    dummy_type dummy_instance;
}

然而,在以下场景中出现了一个问题:

  1. A类开始解构
  2. dummy_instance场被破坏
  3. 事件发生
  4. 由于event_connection尚未被销毁而调用回调
  5. 回调试图访问已释放的内存,程序崩溃
因此,我需要我的event_connection_token总是在回调使用的任何类成员之前被销毁。现在,如果我想让其他100个程序员使用这个事件回调系统,那么期望他们总是在他们创建的所有类中首先释放event_connection_token是不专业的。我们终于来到了这个问题:

我怎么能强制每个客户端删除event_connection_token之前的任何其他在客户端类被销毁?

我在找:

  • 一个聪明的设计,将确保令牌总是首先被删除,程序员甚至没有想到它,或者
  • 一个编译时/运行时检查,让程序员知道他们需要修改代码,以便首先删除令牌。

EDIT:标记为重复的问题不能解决我的问题。我知道对象的销毁顺序,甚至在析构函数中显式调用.reset()都可以解决我的问题。然而,这不是解决我问题的办法。问题是我不想依赖于项目中的每个开发人员都记住这个规则(因为这个事件回调系统将在代码的许多地方使用)。

交换声明

class A
{
    A()
    {
        event_connection = get_dispatcher().connect(event, std::bind(member_function, this));
    }
    void member_function()
    {
        dummy_instance++; //any action that uses this field
    }
    // changed from shared to unique to avoid confusion
    //std::shared_ptr<event_connection_token> event_connection;
    dummy_type dummy_instance;
    std::unique_ptr<event_connection_token> event_connection;
}

的销毁顺序与声明顺序相反(因为构造是按照声明顺序进行的)。现在销毁实例时,首先调用实例的析构函数,然后销毁event_connection,最后销毁dummy_instance(按相反的顺序进行构造)。

我认为你必须接受这样一个事实:如果你不想在阻止他们做"愚蠢"的事情上走得太远,你就必须遵守一些规则来保证这一点(我甚至不认为你可以涵盖所有的角落情况)。

如果你不能要求他们把event_connection放在最后,那么你必须禁止他们通过组合添加它(即使你添加它,你最终会要求他们显式删除指针)。这将首先排除A中的event_connection,而只允许event_connectionA的引用,如果使用智能指针,这将工作得很好(除了这意味着A对象将保留event_connection)。

您可以尝试将实际的回调实现排除到一个单独的类中,然后将其组合到一个"keeper"类中:

class ACallback
{
    public:
        void member_function() 
        {
            dummy_instance++; //any action that uses this field
        }
    private:
        dummy_type dummy_instance;
}
class A 
{
    A(ACallback *callback) : callback(callback)
    {
        event_connection = get_dispatcher().connect(event, std::bind(ACallback::member_function, callback));
    }
    ~A()
    {
        // make sure callback will not be used any more
    }
    std::unique_ptr<ACallback> callback;
    std::unique_ptr<event_connection_token> event_connection;
}