gpt4 book ai didi

c++ - 如何防止调用函数调用正在被销毁的子类的实例

转载 作者:搜寻专家 更新时间:2023-10-31 02:16:50 24 4
gpt4 key购买 nike

我不得不修复一个难以发现的错误,但我对这个修复并不满意。我们的应用程序是在 Windows 中运行的 C++,错误是纯虚拟调用崩溃。这是一些背景:

class Observable
{
public:
Observable();
virtual ~Observable();
void Attach(Observer&); // Seize lock, then add Observer to the list
void Detach(Observer&); // Seize lock, then remove Observer from the list
void Notify(); // Seize lock, then iterate list and call Update() on each Observer

protected:
// List of attached observers
};

class Subject : public Observable
{
// Just important to know there is a subclass of Observable
}

class Observer
{
public:
Observer();
virtual ~Observer(); // Detaches itself from the Observable
void Update() = 0;
};

class Thing : public Observer
{
public:
void Update(); // What it does is immaterial to this question
};

因为这是一个多线程环境,所以 Attach()、Detach() 和 Notify() 都有锁。 Notify() 获取锁,然后迭代观察者列表并在每个观察者上调用 Update()。

(我希望这足以作为背景介绍,而不必发布完整的代码。)

当一个观察者被摧毁时,问题就出现了。在销毁时,Observer 从 Observable 中分离出来。同时,在另一个线程中,正在对 Subject 调用 Notify()。我最初的想法是,由于 Detach()(在销毁 Observer 时调用)和 Notify() 中的锁,我们受到了保护。但是,C++ 先销毁子类,然后再销毁基类。这意味着,在获得阻止 Notify() 函数继续执行的 Detach() 中的锁之前,纯虚拟 Update() 函数的实现被破坏了。 Notify() 函数继续(因为它已经获得了锁)并尝试调用 Update()。结果是崩溃。

现在,这是我的解决方案,它有效,但给我一种反胃的感觉。我将 Update() 函数从纯虚拟更改为虚拟,并提供了一个什么都不做的主体。这让我感到困扰的原因是 Update() 仍在被调用,但是是在一个部分破坏的对象上。换句话说,我正在逃避某些事情,但我对实现并不狂热。

讨论的其他选项:

1) 将锁定移动到子类中。不可取,因为它迫使每个子类的开发人员重复逻辑。如果他忽略了锁定,就会发生不好的事情。

2) 通过 Destroy() 函数强制销毁观察者。老实说,我不确定如何为基于堆栈的对象实现这一点。

3) 让子类在其析构函数中调用“PreDestroy()”函数以通知基类即将销毁。我不知道如何强制执行此操作,忘记它可能会导致难以发现的运行时错误。

任何人都可以就防止此类崩溃的更好方法提出任何建议吗?我有一种不愉快的感觉,我想念房间里的大象。

刺拳

最佳答案

这个问题说明了多线程设计的一个更普遍的结果:受多线程影响的任何对象都不能保证在任何时间点都不能同时访问它自己。这个后果就是房间里的大象,它给您带来了您在问题末尾描述的不愉快的感觉。

简而言之,您的问题是 Attach()Detach()Notify() 都负责抓取适当的锁定并做他们的事情。他们需要能够假设锁在被调用之前已被获取。

不幸的是,该解决方案需要更复杂的设计。一些独立于您的对象(或类)的单一来源有必要调解所有对象的构造、更新(包括附加和分离)和销毁。并且有必要防止任何这些过程独立于调解器发生。

无论您是通过技术手段(例如访问控制等)阻止这些进程,还是简单地声明所有类型都必须遵守的策略,都是一种设计选择。该选择取决于您是否可以依靠您的开发人员(包括您自己)来遵循政策指南。

关于c++ - 如何防止调用函数调用正在被销毁的子类的实例,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36484706/

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