【问题标题】:Dangling Pointers after Destructor is called调用析构函数后的悬空指针
【发布时间】:2016-12-19 04:50:32
【问题描述】:

我通过this post 有一个疑问。将对象的元素在其析构函数中归零是一种好习惯吗? 当对象超出范围时将调用析构函数,但其​​元素是否需要在析构函数中设置为 NULL 以确保不留下悬空指针。

【问题讨论】:

  • 为什么在你的程序中使用原始指针?
  • 您应该使用不属于自己的原始指针。然而,在大多数情况下,现在最好使用“裸”newdelete

标签: c++ pointers


【解决方案1】:

对象被销毁后,它就不复存在了。当这些值将立即不复存在时,将其成员设置为特定值是没有意义的。

delete指向NULL 指向的对象时,设置指向NULL 的指针的模式是非常有害的,并且过去曾导致错误。除非有特定原因需要将指针设置为NULL(例如,稍后可能会针对NULL 进行测试),否则它应该设置为NULL。 p>

考虑:

Foo* foo getFoo();
if (foo!=NULL)
{
    do_stuff();
    delete foo;
}
// lots more code
return (foo == NULL);

现在,想象一下如果有人在这段代码中的delete foo; 之后添加foo = NULL;,认为你应该这样做。现在代码会给出错误的返回值。

接下来,考虑一下:

Foo* foo getFoo();
Foo* bar = null;
if (foo != NULL)
{
    bar = foo;
    do_stuff(bar);
    delete bar;
    bar = NULL;
}
// lots more code
delete foo;

我们总是在delete 之后设置指向NULL 的指针,所以这个delete foo; 一定是安全的,对吧?显然不是。因此,在 delete 之后设置指向 NULL 的指针既没有必要也不够。

别这样。

【讨论】:

    【解决方案2】:

    没有必要在析构函数中将成员元素设置为 NULL,因为已经在所有者对象上调用了 delete 以便调用该析构函数。删除对象的代码有责任不再尝试访问该对象的内容。

    您还使用了额外的循环来清除该内存。

    【讨论】:

    • 周期不应该是一个问题,因为在大多数情况下,当您等待 CPU 获取时,这些 CPU 周期无论如何都会被浪费,尤其是在缓存未命中的情况下。
    【解决方案3】:

    这样做的目的是在发生编程错误时提供确定性行为。

    • 如果使用已删除的指针,则程序在取消引用 nullptr 时总是会失败。 (不允许程序继续。)
    • 如果已删除的指针设置为 nullptr,然后再次被删除,则第二次尝试是 noop(设计使然)。

    这是未在析构函数中删除的指针的正常模式。 (智能指针是你的朋友,完全可以避免这种情况。)

    在析构函数中使已删除的成员指针为空的目的不太明显;当怀疑其他代码可能引用该成员时。这通常应该避免(依赖于此),因为一旦销毁的类的内存被回收,它的效用就很有限。虽然依赖于实现,但在许多环境中,内存的寿命足以在重新使用删除的内存时导致程序失败,以便程序员可以找到问题并修复它。

    【讨论】:

    • 我说的是对成员指针的引用。另一种常见的情况(不是这个问题的一部分):在 C 代码的 C++ 包装器中。因此,指针是在 C++ 代码中定义的,它将通过将句柄(指针到指针)传递给 C API 来初始化,该 C API 具有自己的用于分配和释放它的原语。这些通过提供这样的句柄来工作。编辑:此评论是为回答他人的评论而提供的,该评论已被删除。
    猜你喜欢
    • 1970-01-01
    • 2021-11-28
    • 2016-03-20
    • 2023-03-31
    • 1970-01-01
    • 1970-01-01
    • 2013-10-14
    • 2013-10-10
    • 2015-12-05
    相关资源
    最近更新 更多