【问题标题】:Memory Deallocating freezes my program内存释放冻结了我的程序
【发布时间】:2013-05-09 15:00:54
【问题描述】:

这不是问题,只是我想回答的问题。

我正在制作带有粒子的 2D 应用程序。在点击处理程序中,我编写了以下代码:

Particle *tempp = new Particle();
tempp->setPosition(mx, my);
particles.push_back(tempp); // typeof particles = std::list<Particle*>
delete tempp; // <- this line is the problem

当我单击时,将在鼠标位置创建一个粒子。大约一秒钟后,它应该会消失,效果很好。消失后我可以再次点击创建一个新粒子。

但是,当我在屏幕上仍有一个粒子时单击时,我的程序会冻结并停止工作。

Particle 类的析构函数及其父类的析构函数都是空的。

不调用delete 我的程序运行良好,即使一次有多个粒子,甚至每帧有多个粒子。我只是想知道是什么导致了这个冻结问题。

【问题讨论】:

  • 您正在将指向 tempp 的指针添加到向量 - 在 tempp 被删除后它指向什么?
  • 为什么要将 tempp 推入列表,然后在后面的行中删除它?您的列表包含指向垃圾的指针,任何访问它们的尝试都可能导致您的程序崩溃。
  • 那么到方法结束后指向tempp的指针还存在吗?如果我删除它,内存会被覆盖吗?
  • @Broxzier 您的列表不是函数本地的,因此即使在方法之外也存在。当您删除时,实际分配的内存被释放(可重复使用//它可能被覆盖,就在那里。但它不在那里供您使用并且它的 UB 取消引用它)指针仍然包含地址。 list 没有超出范围,因此它仍然具有带有地址的指针。您可能正在取消引用 deleted 内存地址(可能用于在屏幕上绘制点,或者可能在超时后尝试擦除它并冻结它)

标签: c++ pointers memory-management


【解决方案1】:

根据发布的代码,particles 容器将包含悬空指针。任何取消引用这些的尝试都是未定义的行为。我假设它们稍后会被使用,否则它们的存储似乎毫无意义。

调用push_back() 不会复制指向的对象,而是复制指针的值(动态分配对象的内存地址)。如果Particle 复制成本低、可复制且不需要多态行为,只需将Particle 存储在容器中即可。否则,建议使用智能指针,例如std::unique_ptr,在从容器中移除时自动销毁Particle

【讨论】:

  • 为什么创建第二个点(虽然第一个点仍然存在)会导致问题?每次调用都会调用点击处理程序,似乎tempp 是函数的本地函数,并且将发生new 内存分配。 (我同意悬空指针)
  • @SuvP,第一个不存在,因为它立即是deleted。如果第二个 PArticle 的创建访问了 particles 中的一个悬空指针,那么是未定义的行为,并且可能是该行为的原因。
  • 查看当前代码并假设其他地方没有发生任何其他事情,该列表不会在其他任何地方使用。 (OP只是添加地址并删除内存//我知道这是不切实际的)那应该不是问题吗? (除了悬空指针)。所以也许 OP 正在其他地方访问list,这可能是导致问题的原因? [只是想正确地清除我的疑问]
  • @SuvP,是的。指向已释放内存的指针本身不是问题,您可以打印指向已释放内存的指针的地址。你不能做的是 dreference 一个指向已释放内存(或未分配内存)的指针。在代码的其他地方,它可能取消引用添加到容器中的指针之一。
  • @Broxzier,其余代码对我来说是不可用的,但错误将是任何尝试使用(取消引用)particles 中的任何指针的代码。
【解决方案2】:

当您将指针推入列表时,您只会推入实际指针的副本,而不会复制它所指向的内容。这意味着在push_back 之后,您有两个 指向相同 内存的指针。

如果您随后释放该内存,则您有一个指向释放内存的指针,该指针现在无效。

【讨论】:

    【解决方案3】:

    当我看到new 和几行之后的delete 时,我宁愿看到使用的堆栈。除非Particle 很大(我对此表示怀疑),否则您可以将代码更改为:

    Particle tempp;
    tempp.setPosition(mx, my);
    particles.push_back(tempp); // change particles to std::list<Particle>
    

    快速。你写的代码更少,你就不会崩溃。

    【讨论】:

    • 感谢您的回答。当然,这是可行的,但我想知道在这种情况下导致问题的原因,而不是解决方案。无需调用 delete 或使用更改矢量来存储实际粒子,它已经可以正常工作了。
    • @Broxzier 它没有正常工作,只是没有爆炸。无论你是什么新的,你都必须删除。您的新代码且没有删除的代码正在泄漏内存。这些天我们有很多,所以它不会伤害你,但它不能正常工作。在这种情况下没有理由使用堆,最好尽可能使用良好的习惯。堆栈语义应该始终是您在 C++ 中的首选
    【解决方案4】:

    我相信解决方案在于您的第三行代码。请注意,粒子是指向粒子的指针的向量?那么,在第 3 行中,您创建指针的副本并将其插入到列表中。在下一行,您释放该指针指向的内存。 该列表不存储您的粒子 - 它仅存储粒子的内存地址因此,当您删除粒子时,您告诉编译器重新使用包含您的有效数据的内存。 p>

    因此,虽然评论第 4 行会使问题消失,但实际上并没有在那里崩溃 - 没有理由这样做。可能的情况是,当尝试使用 曾经属于你但在第 3 行被释放的内存时,它会崩溃。

    您可以让列表存储实际的粒子作为修复。

    【讨论】:

      【解决方案5】:

      您将pointer 放入容器中,然后将其删除,这是一个问题。 push_back 将复制pointer 的值而不是pointer 的内容,因此当您调用delete 时,容器中的pointer 不再有效。所以现在你有一个悬空指针,当你取消引用它时,这将是未定义的行为,但很可能是崩溃。

      【讨论】:

        猜你喜欢
        • 2019-09-08
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-06-14
        • 1970-01-01
        • 2015-12-26
        • 2017-11-02
        相关资源
        最近更新 更多