为什么标记删除析构函数是因为Windows上的向量删除而被调用的?

nop*_*plk 6 c++ debugging destructor memory-leaks vector

我有一个在Windows上泄漏的代码.它在许多unix平台上运行正常,泄漏只发生在Windows上.二进制文件由exe,1 dll和2个静态库组成.exe链接到dll和静态库,而静态库也链接到dll.当代码调用向量删除析构函数时,在exe代码中发生泄漏,由于某种原因,标量删除析构函数被调用.这导致只删除数组中的第一个对象,而数组的其余部分保留在内存中.

泄漏的伪代码如下所示:

class MyClassFromExe : public MyBaseClassFromDll {
  public:
    ClassFromDll* m_arr;

    MyClassFromExe(unsigned int size)  
    {
      m_arr = new ClassFromDll[size];
    }

    ~MyClassFromExe() 
    {
      delete [] m_arr;
    }
};

void func()
{
  MyClassFromExe obj(3);
}
Run Code Online (Sandbox Code Playgroud)

当func()完成并且析构函数被调用时,我看到只调用了m_arr中第一个对象的析构函数.从调试器我看到这​​是通过标量删除析构函数而不是从矢量删除析构函数完成的.这解释了为什么只有第一个对象被销毁.我需要理解的是,当使用delete []时,为什么要调用标量删除析构函数?

我找到了这个线程 - 为什么矢量删除析构函数是由于标量删除而被调用的?.我按照那里的建议,确保所有模块都使用/ MD编译.

重要的是要注意,当包含ClassFromDll的dll是静态库而不是dll时,一切正常.仅当静态库更改为dll时才会启动泄漏.当程序在Release模式下泄漏时,它会在delete [] m_arr上的Debug模式下崩溃.崩溃发生在dbgdel.cpp第52行--_BLOCK_TYPE_IS_VALID(pHead-> nBlockUse)中.

在unix平台上,这个lib也是一个共享库,正如预期的那样,在那里调用删除析构函数并且没有泄漏.可能问题出在VC编译器上吗?或者可能需要更改项目的其他一些设置?我正在使用VC2003.

先感谢您!

Mik*_*son 0

我认为这是在一个堆上分配并在另一个堆上删除的明显情况(请记住,delete[] 必须在堆中查询数组中的元素数量,如果堆甚至不包含此指针,它将返回“错误”(不是真的),并且将假定它只是一个元素并使用标量删除代替)。我认为您遇到的问题在尝试将其归结为简单的示例代码时丢失了。我建议您阅读这篇文章(它很旧,但删除技术仍然非常相关,我自己使用该技术的变体,它的作用就像一个魅力)。一种现代的方法是将删除函数指针附加到处理对象的智能指针(shared_ptr),这样,通过在工厂函数中创建对象的同时分配此删除函数指针,您可以确保删除将在分配它的同一个堆上调用。