C++ 新对象导致堆损坏

C++ 新对象导致堆损坏,c++,heap,gflags,C++,Heap,Gflags,几天来,我一直在与堆损坏问题作斗争。vs 2005调试器首先警告我,在删除以前新建的对象后,我可能损坏了堆。对此问题的研究导致我使用gflags和页面堆设置。为我的特定图像启用此设置后,它可能会将我指向实际导致损坏的行 Gflags将问题对象的构造函数确定为罪魁祸首。对象派生如下: class POPUPS_EXPORT MLUNumber : public MLUBase { ... } class POPUPS_EXPORT MLUBase : public BusinessLog

几天来,我一直在与堆损坏问题作斗争。vs 2005调试器首先警告我,在删除以前新建的对象后,我可能损坏了堆。对此问题的研究导致我使用gflags和页面堆设置。为我的特定图像启用此设置后,它可能会将我指向实际导致损坏的行

Gflags将问题对象的构造函数确定为罪魁祸首。对象派生如下:

class POPUPS_EXPORT MLUNumber :  public MLUBase
  {
...
  }
class POPUPS_EXPORT MLUBase : public BusinessLogicUnit
  {
...
  }
我可以在单独的线程中实例化一个MLUNumber,并且不会发生堆损坏

我可以实例化另一个类,该类也继承自MLUBase,不会导致堆损坏

访问冲突是由于构造函数的左大括号上发生损坏而引发的,这似乎是由于隐式初始化对象(?)

基类构造函数(MLUBase)成功完成

从VS2005中的内存窗口中可以看出,似乎没有为实际对象分配足够的空间。我的猜测是,只为基类分配了足够的资源

导致故障的线路:

BusinessLogicUnit* biz = new MLUNumber();
我希望找到一个可能导致这种情况的原因,或者接下来是另一个故障排除步骤

BusinessLogicUnit不是MLUNumber。你为什么要这样分配?相反 BusinessLogicUnit*biz=新的BusinessLogicUnit()

如何删除内存?使用基类指针?您是否已将
BusinessLogicUnit
的析构函数设置为虚拟?它必须是虚拟的

class BusinessLogicUnit
{
  public:
      //..
      virtual ~BusinessLogicUnit(); //it must be virtual!
};

<> P>通过基类指针删除派生类对象,调用C++标准的未定义行为。

< P>不幸的是,由于所给出的信息,无法确定问题。 您可能需要检查以下内容:

  • 确保BusinessLogicUnit具有虚拟析构函数。当通过基指针删除对象时,基类中必须存在虚拟析构函数,子类才能正确析构函数
  • 确保生成的所有源文件都具有相同的预处理器标志和编译器选项。标志的差异(可能是调试/发布标志之间的差异?)可能会导致结构大小的变化,从而导致不同源文件中报告的大小不一致
  • 即使使用gflags设置,某些类型的堆损坏也可能未被检测到。审核您的其他堆使用情况,以尝试找到问题的根源。理想情况下,您应该将可靠崩溃的最小测试用例放在一起,但活动量最少,这样您就可以缩小导致崩溃的原因
  • 尝试一个干净的解决方案并重建;我偶尔会看到时间戳被搞砸,一个旧的对象文件可能会使用过时的结构定义。至少值得检查:)

    • 或者你做了类似的事情

      struct A
      {
          SomeType & m_param;
      
          A(SomeType & param) : m_param(param)
          {
              ...use m_param here...
          }
      };
      
      A a(SomeType()); // passing a temporary by reference
      

      那么这就是未定义的行为,因为引用的临时文件在
      m_param(param)
      发生后立即死亡。

      我同意bdonlan的观点,即没有足够的信息来找出问题所在。这里有很多好的建议,但仅仅猜测应用程序崩溃的可能原因并不是解决问题的明智方法


      通过启用检测(pageheap)来帮助您缩小问题范围,您做了正确的事情。我将继续沿着这条路走下去,确切地找出导致访问冲突的内存地址(以及地址的来源)。

      能否请您发布一个可以重现问题的代码的最小示例?根据您提供的信息,我们所能做的只是提供一些有根据的猜测。如果您不能仅通过在VS2005调试器中运行调试版本的代码来解决这个问题,我会非常惊讶。这将启用额外的堆检查,该检查应在错误发生时而不是在以后的随机时间检测错误。是否启用了完整的pagheap?我已通过gflags.exe启用了完整的页面堆。我在vs2005中找不到启用它的设置。目前,仅vs2005(没有gflags)在我销毁对象时会警告我以前损坏了堆。创建对象不会导致堆损坏。但是,它通常可以检测在程序执行过程中的任何时候可能发生的堆损坏。关于损坏的数据,你不能判断它是否损坏,除非你做一些依赖于它是否损坏的事情。这是一个完全合理的做法-BusinessLogicUnit可以是一个抽象接口类。只要析构函数是虚拟的,它本身就完全安全。不,它不是:MLUNumber不在BusinessLogicUnit的层次结构中。星期五晚上:我一定不能醒着。@John,那不是真的-它是。这真的只是为了调试的理智。最初的调用是SomeObject->Switch(new-bluecure);。我已经确认MLUNumber*biz5=新的MLUNumber();也会导致崩溃。是:virtual~BusinessLogicUnit(void);请记住,在构建时而不是销毁时会引发访问冲突(由于gflags和页面堆设置)。这让我认为构造函数是罪魁祸首。所有的析构函数都是虚拟的。我将检查预处理器标志。不过,我肯定在调试所有版本。我不知道如何更好地测试堆损坏。我每次都能重现,但不知道是什么原因造成的。我已经尝试过干净的解决方案,我正在交叉手指:)@reuscam,这里的关键字是“minimal”-开始删除代码,看看它是否还能复制。最后,希望你能找到问题所在。希望如此。最后的答案是dll和从dll中提取头的exe之间的字节对齐方式不同。这真的来了
      struct A
      {
          SomeType & m_param;
      
          A(SomeType & param) : m_param(param)
          {
              ...use m_param here...
          }
      };
      
      A a(SomeType()); // passing a temporary by reference