当人们忘记调用虚拟的基类版本时,有没有办法扫描?

时间:2009-06-23 01:54:19

标签: c++ memory

我刚刚修复了由于某人忘记调用超类的OnUnload而导致的内存泄漏。超类版本释放了一些资源(就像它的超类一样)。

是否有外部静态分析工具,或者至少有某种运行时技巧可以检测到这一点?能够明显地做出异常(尽管这些情况非常罕见)。

更新:根据以下答案,我需要添加特定于我们设置的约束,这是Wii / 360 / PS3的游戏。针对特定应用的非常具体的引擎。

  • 我们有一个深层次的游戏对象类层次(我从未同意的设计,但它是我们发布的设计)。实际上是深远的。我将为下一个游戏重做这个以使用Dungeon Siege风格的基于组件的系统,但在我们当前的代码库中,深层次结构使得DispatchVirtual() - > onVirtual()模式难以应用。

  • 不会为我们的游戏对象调用析构函数,因为不会调用delete。在世界加载期间,游戏对象进入仅添加(堆栈)分配器的池。在关卡结束时,我只需将堆栈指针设置回低水位标记即可立即释放所有内容。事先,我们迭代所有对象并在它们上调用OnUnload,以便它们可以释放它们使用的任何外部资源。你可以称之为“垃圾收集:核选项”。所以没有析构函数。

  • 即使我们可以使用基于析构函数的方法,它也只能解决OnUnload或OnFree的狭隘问题,而不能解决OnUpdate,OnWorldMessage,OnLoaded等问题。

运行时解决方案很有趣,但我讨厌依靠测试来捕获它。 Optimal可以是编译时模板技巧,也可以是我可以使用的外部静态分析工具。

3 个答案:

答案 0 :(得分:7)

不要相信派生类这样做;使用template method design pattern确保您的基类行为始终发生:

class Base
{
   public:
      void OnUnload()
      {
          // Do stuff that must always be done.
          this->doOnUnload();
      }
   private:

      // Virtual method for derived classes to override.
      // Can be pure virtual if it will always be overridden.
      virtual void doOnUnload()
      {
         // Empty default implementation
      }
};

唯一的问题是,这只会为您带来一级继承,而您的问题则表明您需要两级继承。在这种情况下,可以重复这种模式。

但一般来说,基类调用特定行为的派生类通常比要求派生类调用基类更稳定。

答案 1 :(得分:4)

您可以使用的运行时“技巧”是,如果您要查找的约束失败,则在基类的析构函数中断言。假设实例被实际销毁并且没有泄露,那么如果合同被正确遵循,这将告诉您当时对象被销毁。

答案 2 :(得分:4)

“运行时技巧”是将资源包装在类中,并确保资源类适当地处理分配/释放。 C ++相对于3G语言的一个主要好处是多重继承。