关于C ++内存分配和删除的问题

时间:2009-10-26 04:38:56

标签: c++ memory-management destructor glibc

我收到了一个错误的错误。当我在一个对象层次结构顶部的对象上调用delete时(希望删除它的子对象),我的程序退出了,我得到了这个:

*** glibc detected *** /home/mossen/workspace/abbot/Debug/abbot: double free or corruption (out): 0xb7ec2158 ***

接下来看起来像某种内存转储。我已经搜索了这个错误,当我试图删除已经删除的内存时,似乎会发生这种错误。不可能,因为我的代码中只有一个地方尝试删除。这是古怪的部分:在调试模式下不会发生。有问题的代码:


Terrain::~Terrain()
{
    if (heightmap != NULL) // 'heightmap' is a Heightmap*
    {
        cout << "heightmap& == " << heightmap << endl;
        delete heightmap;
    }
}

我已经在高度图析构函数中注释掉了所有内容,但仍然存在此错误。发生错误时,

heightmap& == 0xb7ec2158

已打印。在调试模式下,我可以慢慢地逐步执行代码

heightmap& == 0x00000000
打印

,没有错误。如果我注释掉'删除高度图;'行,错误永远不会发生。上面的析构函数是从另一个析构函数(单独的类,没有虚拟析构函数或类似的东西)调用的。高度图指针在这样的方法中是新的:


Heightmap* HeightmapLoader::load() // a static method
{
   // ....
   Heightmap* heightmap = new Heightmap();
   // ....other code
   return heightmap;
}

是否与返回在静态方法的堆栈空间中初始化的指针有关?我正确地删除了吗?关于我可以检查或做得更好的任何其他提示?

4 个答案:

答案 0 :(得分:2)

如果永远不会调用load(),会发生什么?你的类构造函数是初始化heightmap,还是在它到达析构函数时是未初始化的?

另外,你说:

  

...删除已删除的内存。不可能,因为我的代码中只有一个地方尝试删除。

但是,您没有考虑到在程序执行期间您的析构函数可能被多次调用

答案 1 :(得分:2)

在调试模式下,指针通常设置为NULL,内存块清零。这就是您在调试/发布模式下遇到不同行为的原因。

我建议您使用智能指针而不是传统指针

auto_ptr<Heightmap> HeightmapLoader::load() // a static method
{
   // ....
   auto_ptr<Heightmap> heightmap( new Heightmap() );
   // ....other code
   return heightmap;
}

这样你以后就不需要删除了它,因为它会自动为你完成

另见boost::shared_ptr

答案 2 :(得分:1)

你很可能两次打电话给那个dtor;在调试模式下,指针恰好在删除时归零,在优化模式下,它是独立的。虽然不是一个干净的解决方案,但我想到的第一个解决方法是在删除后立即设置heightmap = NULL; - 它不应该是必要的,但是当你正在寻找你为什么要解释时肯定不会受到伤害重新摧毁一些Terrain实例两次! - )[[你所展示的少量代码中没有任何内容可以帮助我们解释双重破坏的原因。]]

答案 3 :(得分:0)

它看起来像是未初始化指针的经典案例。正如@Greg所说,如果没有从Terrain调用load()怎么办?我认为你没有初始化HeightMap*构造函数中的Terrain指针。在调试模式下,此指针可以设置为NULL,C ++保证删除NULL指针是一个有效的操作,因此代码不会崩溃。但是,在发布模式下由于优化,指针处于未初始化状态,并且您尝试释放一些随机内存块并发生上述崩溃。