【问题标题】:Delete on already deleted object : behavior?删除已删除的对象:行为?
【发布时间】:2012-01-20 01:34:42
【问题描述】:

我想知道如果我尝试对已删除或可能尚未分配的指针执行 delete 会发生什么?我读过两件事:首先,delete 操作员会做一些检查,我们不需要检查指针是否为空;然后,我读到它可能导致未知的行为..

我问它,因为我使用了一些包含 Qt 对象属性的个人对象;我认为当我们关闭窗口时 Qt 会删除所有关联的小部件,但我不太确定并且仍然:如果在窗口关闭之前发生软崩溃,我们必须手动删除所有对象。

那么,最好的解决方案是什么?类似的东西?

if( my_object )
    delete my_object;

能避免危险行为吗?

【问题讨论】:

  • 只希望它会正常崩溃,而不是失去您的业务
  • @sehe:哈哈。我想象未来标准中的文本 - 正确的崩溃行为应该正确崩溃
  • 学习现代 C++,并且从不使用delete

标签: c++ pointers memory-management delete-operator


【解决方案1】:

delete 在已经 deleted 的非空指针上是未定义的行为 - 您的程序可能会崩溃。您可以安全地在空指针上使用 delete - 它会产生无操作。

所以真正的问题不是空指针上的delete。真正的问题在这里:

 ptr = new Something();
 otherPtr = ptr;
 delete ptr;
 delete otherPtr;

如果您有多个指向同一个对象的指针,就会发生这种情况,而且非常危险。可能的解决方案是:

  • 使用智能指针(代码中没有delete)或
  • 只有一个指定的指针来控制每个对象的生命周期,而delete 恰好在正确的时间。

【讨论】:

  • “可能会崩溃”是轻描淡写的说法,UB 可以让猛禽从你的窗户跳进来,让宇宙内爆。
  • @refp:我知道,但新手通常不相信。
  • 您的回答具有误导性,您是说 delete 将指针设置为 0?它没有。 delete ptr;delete ptr; 同样危险。
  • @Joe McGrath:不,我不是这么说的。 delete ptr; delete ptr; 的问题在于人们拒绝它为“愚蠢,没有人这样做”。
  • @sharptooth 我不确定“可能的崩溃”。至少我使用过一种实现,第二次删除将是空操作。除非内存已经被重新分配,在这种情况下,新的所有者会有点意外:-)。众所周知,在未定义行为的情况下,最常见的“行为”是程序与您的所有测试完美配合,然后在重要客户端面前的演示中崩溃。
【解决方案2】:
if( my_object )
    delete my_object;

是多余的。 delete 上的 NULL 指针什么也不做。这是由标准保证的。

delete 在已删除的指针上会导致未定义的行为。这就是为什么你应该记住在删除它们之后将指针分配给NULL

delete p;
p = NULL;

编辑:根据 cmets,我觉得我应该指定这一点。如果您有多个指向同一个对象的指针,则分配给 NULL 不会使删除安全。无论如何,最好使用智能指针。

【讨论】:

  • 我不同意这个建议。一方面,它可能会使问题变得更糟,因为你会养成这样的习惯:如果你有一个非 NULL 值的指针,那么delete 它是安全的,但事实并非如此。 (有关示例,请参见尖牙的答案。)
  • 这只会使错误静音。让它崩溃,这样你就可以摆脱双重删除/被提醒使用智能指针。
  • 有一个解释here在删除一个对象后设置给指针的值是什么。
【解决方案3】:

请注意,删除指针不会将其设置为 NULL。

int* i = new int;
*i = 42;
delete i;
delete i; // oops! i is still pointing to the same memory, but it has been deleted already

删除空指针没有任何作用,删除已删除的对象将导致未定义的行为。

【讨论】:

    【解决方案4】:

    正确的做法是:

    if( my_object )
    {
        delete my_object;
        my_object = NULL;
    }
    

    因为,以以前的方式调用两次会在 deleted 指针上调用 delete

    【讨论】:

      【解决方案5】:

      如果您已经在 deleted 指针上调用 delete,则会导致 未定义行为
      但是,在 NULL 指针上调用 delete 无效。

      标准 c++03 § 3.7.4.2-3

      如果释放函数因抛出异常而终止,则行为未定义。提供给释放函数的第一个参数的值可以是空指针值;如果是这样,并且如果释放函数是标准库中提供的函数,则调用无效。否则,提供的值 标准库中的 to operator delete(void*) 应是先前调用标准库中的 operator new(std::size_t)operator new(std::size_t, const std::nothrow_-t&) 返回的值之一,并且提供给标准库中 operator delete[](void*) 的值应为先前调用 operator new[](std::size_t) 或返回的值之一 operator new[](std::size_t, const std::nothrow_t&) 在标准库中。

      使用 RAII 和智能指针 是避免此类问题的最佳武器。

      【讨论】:

        【解决方案6】:

        只是结合上面的答案:

        • if (my_object) 检查指针的值,而不是对象的存在。如果它已被删除,则指针可能仍指向该位置。
        • 删除已删除的对象是未定义的行为,可能会使您的程序崩溃。
        • 删除 NULL 已定义且不执行任何操作。这与第 1 点一起解释了 Luchian 的答案。

        总结一下:你必须清楚谁拥有该对象以及指向该对象的不同指针在哪里。删除对象时,请确保将指向该位置的所有指针设置为 0/NULL。使用 boost::shared_pointer 或 QPointer 等管理对象来帮助您完成这项任务。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2022-07-22
          • 2011-01-12
          • 2012-07-23
          • 1970-01-01
          • 1970-01-01
          • 2019-08-10
          • 2022-06-14
          • 1970-01-01
          相关资源
          最近更新 更多