【问题标题】:Questions about C++ memory allocation and delete关于C++内存分配和删除的问题
【发布时间】:2010-12-10 00:50:33
【问题描述】:

我遇到了一个严重的错误。当我在对象层次结构顶部的对象上调用 delete 时(希望导致其子对象的删除),我的程序退出并得到以下信息:

*** 检测到 glibc *** /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;
    }
}

我已经注释掉了高度图析构函数中的所有内容,仍然是这个错误。发生错误时,

高度图& == 0xb7ec2158

被打印出来。在调试模式下,我可以慢慢地单步执行代码并

高度图& == 0x00000000

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


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

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

【问题讨论】:

    标签: c++ memory-management destructor glibc


    【解决方案1】:

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

    另外,你说:

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

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

    【讨论】:

    • 是的,就是这样。我认为肯定会设置 heightmap*(不是在构造函数中,而是在 setter 方法中),可惜不是。谢谢,格雷格!
    • 在构造过程中始终初始化所有指针。可以安全地删除空指针(无操作)。如果您的构造函数在初始化列表中将指针设置为 0,那么代码从一开始就是正确的。
    • 当然也可能存在复制构造和/或赋值使两个对象指向同一个内存区域...
    【解决方案2】:

    您很可能两次调用该 dtor;在调试模式下,指针恰好在删除时归零,在优化模式下,它会被单独放置。虽然不是一个干净的解决方案,但想到的第一个解决方法是在删除后立即设置heightmap = NULL;——这不应该是必要的,但在你寻找你为什么要破坏的解释时肯定不会受到伤害一些地形实例两次!-) [[在你展示的少量代码中绝对没有任何东西可以帮助我们解释双重破坏的原因。]]

    【讨论】:

      【解决方案3】:

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

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

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

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

      另见boost::shared_ptr

      【讨论】:

      • 谢谢,我没有意识到调试模式...我习惯用Java编码...我会研究一下auto_ptr!
      • +1,还可以查看来自 boost 或 std::tr1 的 scoped_ptr&lt;&gt;unique_ptr&lt;&gt;。它们是智能指针内存管理的不同解决方案。
      【解决方案4】:

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-08-27
        • 1970-01-01
        • 1970-01-01
        • 2011-03-03
        • 1970-01-01
        • 2011-03-24
        • 1970-01-01
        • 2021-11-27
        相关资源
        最近更新 更多