2

在我的项目中,我有一个事件系统。您可以将回调连接到事件,并且只要发送事件,就会调用您的回调。

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

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在客户端类中的其他任何内容被破坏之前删除?

我正在寻找:

  • 一个聪明的设计,可以确保令牌总是在没有程序员考虑的情况下首先被删除,或者
  • 编译时/运行时检查,让程序员知道他们需要修改代码以便首先删除令牌。

编辑:标记为重复的问题不能解决我的问题。我知道对象的破坏顺序,甚至明确调用.reset()析构函数将解决我的问题。然而,这不是我的问题的解决方案。问题是我不想让项目中的每个开发人员都记住这条规则(因为这个事件回调系统将在代码中的许多地方使用)。

4

2 回答 2

1

只需交换声明

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最后,那么你必须禁止他们通过组合添加它(即使你完全添加它,你最终会要求他们明确删除指针)。这将首先排除event_connectionin A,而是只允许event_connection引用A,如果您使用智能指针,这将很好地工作(除非这意味着该A对象将一直event_connection保留)。

于 2015-08-14T10:40:39.070 回答
0

您可以尝试将实际的回调实现排除在一个单独的类中,然后将其组合成一个“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;
}
于 2015-08-14T10:17:27.900 回答