删除 "this" 指针后阻止对象使用
block object usage after deletion of "this" pointer
我正在开发一个存在以下问题的应用程序。基本上有很多对象可能会隐式地破坏自己。
void Foo::func()
{
...
Bar b;
b.func2();
}
此处 func2
可能会破坏调用它的 foo
对象。由于这可能发生的情况不是很明显,我想确保在此调用后不能访问 foo
对象的任何成员变量,因为我不能保证它们仍然有效。如果对 b 的调用是最后一次调用,我完全没问题,但由于我不是唯一一个在这个项目上工作的人,而且破坏并不明显,我想在这些调用后实现一些东西来阻止使用 this
。有没有一种方法可以在不完全重构当前设计的情况下实现这一点(因为它在整个项目中被广泛使用)?
一些背景信息:
这是一个 Qt UI 应用程序,它使用 QML 来跟踪一堆 "screens"(屏幕是 QML + 其对应的 C++ 模型)。我示例中的 Bar
class 是控制屏幕生命周期的 'stack manager'。这是一个单身人士(我知道)。 Foo
class 是特定 QML 的 C++ 模型。函数 Foo::func()
是一个可以从 QML 中的用户输入或另一个系统事件调用的函数。该函数通常会处理该事件,但有时它会告诉屏幕管理器删除一个或多个屏幕,这又会删除与该屏幕对应的模型(可能是调用模型)。
严重的设计问题?
无法阻止this
指针。与所有原始指针一样,在取消引用之前必须确保它是有效的。
但这还不是全部:如果调用 fun2()
的 Foo
是自动存储持续时间的本地对象怎么办?
- 如果您通过调用其析构函数来销毁函数调用中的对象,则必须确保在同一位置仍然存在有效对象:否则在将块留在其中时会自动调用析构函数定义对象的位置可能会导致未定义的行为。
- 如果您
delete
对象而不是仅仅销毁它,它将是未定义的 behavior in any case。
带有智能指针的替代设计
解决这种情况的一种方法是使用 factories 创建所有 Foo
和 Bar
对象(确保构造函数不是 public),并让这些工厂 return shared_ptr
.
这样做的好处是如果一个对象不再被使用,它会自行销毁。这比手动管理销毁要干净得多。
你会面临几个挑战:
- 您必须重构所有代码才能用智能指针替换原始指针
- 为了避免由于交叉引用(两个对象保持彼此的 slart 指针)而导致的无休止的生活,您需要弄清楚何时使用
shared_ptr
(如果指针必须确保对象仍然存在)以及何时使用 weak_ptr
(即无助于保持对象存活的指针)。
带状态的替代设计
另一种选择是使用状态来区分可以使用的活动对象和不再使用的已故对象。因此,不是删除对象,而是调用状态更改函数,该函数 clean/reset 对象。
这可以实现:
- 要么非常适合 state design pattern(但这可能需要进行大量重构),
- 或者用一个简单的标志。然后将在每个成员函数的开头检查它,并在访问可能更改对象状态的调用之后的数据成员之前进行检查。这仍然容易出错并需要分析,但主要需要“本地”更改,从而为重构提供更大的灵活性。
这种方法的优点是状态改变函数将非常简单(你目前在析构函数中的大部分事情,但避免它们可能会意外地第二次完成)并且使棘手的部分非常可见。
难点在于确保死去的物体得到永久清洁。因此,您需要解决前面提到的所有权问题,并确保对象不会在操作过程中被删除。
我正在开发一个存在以下问题的应用程序。基本上有很多对象可能会隐式地破坏自己。
void Foo::func()
{
...
Bar b;
b.func2();
}
此处 func2
可能会破坏调用它的 foo
对象。由于这可能发生的情况不是很明显,我想确保在此调用后不能访问 foo
对象的任何成员变量,因为我不能保证它们仍然有效。如果对 b 的调用是最后一次调用,我完全没问题,但由于我不是唯一一个在这个项目上工作的人,而且破坏并不明显,我想在这些调用后实现一些东西来阻止使用 this
。有没有一种方法可以在不完全重构当前设计的情况下实现这一点(因为它在整个项目中被广泛使用)?
一些背景信息:
这是一个 Qt UI 应用程序,它使用 QML 来跟踪一堆 "screens"(屏幕是 QML + 其对应的 C++ 模型)。我示例中的 Bar
class 是控制屏幕生命周期的 'stack manager'。这是一个单身人士(我知道)。 Foo
class 是特定 QML 的 C++ 模型。函数 Foo::func()
是一个可以从 QML 中的用户输入或另一个系统事件调用的函数。该函数通常会处理该事件,但有时它会告诉屏幕管理器删除一个或多个屏幕,这又会删除与该屏幕对应的模型(可能是调用模型)。
严重的设计问题?
无法阻止this
指针。与所有原始指针一样,在取消引用之前必须确保它是有效的。
但这还不是全部:如果调用 fun2()
的 Foo
是自动存储持续时间的本地对象怎么办?
- 如果您通过调用其析构函数来销毁函数调用中的对象,则必须确保在同一位置仍然存在有效对象:否则在将块留在其中时会自动调用析构函数定义对象的位置可能会导致未定义的行为。
- 如果您
delete
对象而不是仅仅销毁它,它将是未定义的 behavior in any case。
带有智能指针的替代设计
解决这种情况的一种方法是使用 factories 创建所有 Foo
和 Bar
对象(确保构造函数不是 public),并让这些工厂 return shared_ptr
.
这样做的好处是如果一个对象不再被使用,它会自行销毁。这比手动管理销毁要干净得多。
你会面临几个挑战:
- 您必须重构所有代码才能用智能指针替换原始指针
- 为了避免由于交叉引用(两个对象保持彼此的 slart 指针)而导致的无休止的生活,您需要弄清楚何时使用
shared_ptr
(如果指针必须确保对象仍然存在)以及何时使用weak_ptr
(即无助于保持对象存活的指针)。
带状态的替代设计
另一种选择是使用状态来区分可以使用的活动对象和不再使用的已故对象。因此,不是删除对象,而是调用状态更改函数,该函数 clean/reset 对象。
这可以实现:
- 要么非常适合 state design pattern(但这可能需要进行大量重构),
- 或者用一个简单的标志。然后将在每个成员函数的开头检查它,并在访问可能更改对象状态的调用之后的数据成员之前进行检查。这仍然容易出错并需要分析,但主要需要“本地”更改,从而为重构提供更大的灵活性。
这种方法的优点是状态改变函数将非常简单(你目前在析构函数中的大部分事情,但避免它们可能会意外地第二次完成)并且使棘手的部分非常可见。
难点在于确保死去的物体得到永久清洁。因此,您需要解决前面提到的所有权问题,并确保对象不会在操作过程中被删除。