C++ 当人们忘记调用虚拟机的基类版本时,是否有一种扫描方法?

C++ 当人们忘记调用虚拟机的基类版本时,是否有一种扫描方法?,c++,memory,C++,Memory,我刚刚修复了一个内存泄漏问题,它是由某人在重写超类时忘记调用超类的OnUnload引起的。超类版本释放了一些资源(它的超类也是如此) 是否有外部静态分析工具,或者至少我可以做一些运行时技巧来检测这一点?有能力做出明显的例外(尽管这种情况非常罕见) 更新:根据下面的答案,我需要添加特定于我们的设置的约束,这是一款Wii/360/PS3游戏。针对特定应用的特定引擎 我们有一个很深的游戏对象类层次结构(我从来都不同意这个设计,但这是我们提供的设计)。实际上,又深又宽。我将在下一个游戏中使用一个地牢围

我刚刚修复了一个内存泄漏问题,它是由某人在重写超类时忘记调用超类的OnUnload引起的。超类版本释放了一些资源(它的超类也是如此)

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

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

  • 我们有一个很深的游戏对象类层次结构(我从来都不同意这个设计,但这是我们提供的设计)。实际上,又深又宽。我将在下一个游戏中使用一个地牢围城式的基于组件的系统,但在我们当前的代码库中,深层的层次结构使得DispatchVirtual()->onVirtual()模式难以应用

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

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


运行时解决方案很有趣,但我讨厌依赖测试来捕捉这一点。最佳选择是编译时模板技巧或我可以使用的外部静态分析工具。

如果要查找的约束失败,则可以使用运行时“技巧”在基类的析构函数中断言。假设实例已实际销毁且未泄漏,这将在销毁对象时告诉您是否正确遵循了约定。

如果要查找的约束失败,您可以使用的运行时“技巧”是在基类的析构函数中断言。假设实例已实际销毁且未泄漏,这将在销毁对象时告诉您是否正确遵守了约定。

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

< P>一个“运行时技巧”是将资源打包在一个类中,并确保资源类适当地处理分配/解除分配。C++在3G语言上的一个主要好处是多重继承。

< P>不要相信派生类来做它;使用确保基类行为始终发生:

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
      }
};
唯一的问题是,这只为您购买了一个级别的继承,而您的问题是您需要两个级别的继承。在这种情况下,此模式可以重复


但一般来说,让基类为特定行为调用派生类通常比要求派生类调用基类更稳定;使用确保基类行为始终发生:

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
      }
};
唯一的问题是,这只为您购买了一个级别的继承,而您的问题是您需要两个级别的继承。在这种情况下,此模式可以重复


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

为什么不将这些内容移动到析构函数中?这就是它的目的。同意,但我们没有析构函数。我们的用法相当具体。我会更新问题的,为什么不把那些东西放到析构函数里?这就是它的目的。同意,但我们没有析构函数。我们的用法相当具体。我将更新这个问题。我们在最基本的类中使用的正是这个模式。但正如你所说,这只适用于每一级的继承。因此,每个派生版本都需要添加新的虚拟对象。我们的游戏对象层次结构很深(我不同意这种设计,但这是我们的代码),因此这将导致过于冗长和混乱。将一个私有bool成员变量添加到类Base(比如baseunload),并将其初始化为false。2.在Base::doUnload()中,将baseUnload设置为true;3.在Base::OnUnload()中,执行运行时检查baseunload是否为true。瞧,您确定任何派生版本对dounnload()的重写都称为Base::dounnload()。这不会捕获DoonLoad()的深度派生重写,它会故意跳过一个级别,但它会捕获一个在重写中忘记调用其父类版本的重写。我们在最基本的类中使用的正是这种模式。但正如你所说,这只适用于每一级的继承。因此,每个派生版本都需要添加新的虚拟对象。我们的游戏对象层次结构很深(我不同意这种设计,但这是我们的代码),因此这将导致过于冗长和混乱。将一个私有bool成员变量添加到类Base(比如baseunload),并将其初始化为false。2.在Base::doUnload()中,将baseUnload设置为true;3.在Base::OnUnload()中,执行运行时检查baseunload是否为true。瞧,您确定任何派生版本对dounnload()的重写都称为Base::dounnload()。这不会捕获DoonLoad()的深度派生重写,它会故意跳过一个级别,但它会捕获一个在重写中忘记调用其父类版本的重写。我们不调用delete,但您知道..我可以手动调用dtor。编译器保证我们沿着对象的整个链前进