删除指针后阻止对象使用 "this"

block object usage after deletion of "this" pointer

本文关键字:对象 this 指针 删除      更新时间:2023-10-16

我正在开发一个有以下问题的应用程序。基本上有很多对象隐含地可能会摧毁自己。

void Foo::func()
{
...
Bar b;
b.func2();
}

在这里,func2可能会破坏调用它的foo对象。由于这种情况发生不是很明显,我想确保在此调用后无法访问foo对象的任何成员变量,因为我不能保证它们仍然有效。如果对 b 的调用是最后一次调用,我完全没问题,但由于我不是唯一一个从事这个项目的人,而且破坏并不明显,我想在这些调用之后实现一些东西来阻止使用this。有没有办法在不完全重构当前设计的情况下实现这一点(因为它在整个项目中被广泛使用)?

一些背景信息:

它是一个Qt UI应用程序,它使用QML来跟踪一堆"屏幕"(屏幕是QML+其相应的C++模型)。我示例中Bar类是控制屏幕生命周期的"堆栈管理器"。这是一个单例(我知道)。Foo类是特定 QML 的C++模型。函数Foo::func()是一个可以从 QML 中的用户输入或其他系统事件调用的函数。该函数通常处理事件,但偶尔它可以告诉屏幕管理器删除一个或多个屏幕,这反过来又会删除与该屏幕对应的模型(可能是调用模型)。

严重的设计问题?

无法阻止this指针。与所有原始指针一样,在取消引用它之前,必须确保它是有效的。

但这还不是全部:如果调用fun2()Foo是自动存储持续时间的本地对象怎么办?

如果要通过调用其析构函数来
  • 销毁函数调用中的对象,则必须确保在同一位置仍然有一个有效的对象:否则,在离开定义对象的块时自动调用析构函数可能会导致未定义的行为。
  • 如果您delete对象而不仅仅是销毁它,那么在任何情况下都是未定义的行为。

带有智能指针的替代设计

摆脱这种情况的一种方法是使用工厂创建所有FooBar对象(确保构造函数不是公共的),并让这些工厂返回shared_ptr

这样做的好处是,如果不再使用一个对象,它将自我毁灭。这比手动管理销毁要干净得多。

但是,您将面临以下几个挑战:

  • 您必须重构所有代码才能用智能指针替换原始指针
  • 为了避免由于交叉引用(两个对象使每个对象保持指向另一个的 slart 指针)而导致无休止的活,您需要弄清楚何时使用shared_ptr(如果指针必须确保对象仍然处于活动状态)以及何时使用weak_ptr(即无助于保持对象活动的指针)。

带状态的替代设计

另一种选择是使用状态来区分可以使用的活动对象和不再使用的已故对象。 因此,您不会删除对象,而是调用一个状态更改函数来清理/重置对象。

这可以实现:

  • 要么很好地使用状态设计模式(但这可能需要一些广泛的重构),
  • 或带有简单的标志。 然后,在每个成员函数的开头,以及在访问可能更改对象状态的调用之后的数据成员之前,对其进行检查。这仍然容易出错,需要分析,但主要需要"本地"更改,从而为重构提供了更大的灵活性。

这种方法的优点是状态更改函数将非常简单(您当前在析构函数中拥有的大多数事情,但避免它们可能会再次意外完成),并使棘手的部分非常明显。

困难在于确保死者物品得到永久清洁。 因此,您需要解决前面已经提到的所有权问题,并确保对象不会在其操作过程中被删除。