【问题标题】:What is the use of "delete this"?“删除这个”有什么用?
【发布时间】:2010-10-01 15:14:01
【问题描述】:

今天,我看到了一些遗留代码。在析构函数中有一个类似“delete this”的语句。我认为,这个调用将是递归的。为什么它有效?

我在Y!上做了一些快速搜索,发现如果需要限制用户创建堆栈对象,我们可以将析构函数设为私有并提供删除实例的接口。在提供的接口中,我们必须对这个指针调用delete。

还有其他使用这种语句的情况吗?

【问题讨论】:

    标签: c++ memory-management destructor self-destruction


    【解决方案1】:

    “delete this”通常用于引用计数的对象。对于一个引用计数的对象,何时删除的决定通常放在对象本身上。下面是一个 Release 方法的示例 [1]。

    int MyRefCountedObject::Release() {
      _refCount--;
      if ( 0 == _refCount ) {
        delete this;
        return 0;
      }
      return _refCount;
    }
    

    ATL COM 对象是这种模式的主要示例。

    [1] 是的,我意识到这不是线程安全的。

    【讨论】:

    • 虽然引用对象的自删除是一种非常常见的模式,但我认为最初的问题是将其放入析构函数中,而不是 Release() 函数,在这种情况下,这简直是疯了。跨度>
    • @rmeador,真的有两个问题。标题和最后一句话都表明想知道“删除这个;”的有效用法。我希望我回答了。中间确实提出了一个“为什么要在 dtor 中删除它”的问题。我同意这样做似乎很疯狂。
    • 您的示例代码有错误。如果 _refCount 是一个成员变量,当你“删除”该成员变量不再存在时,你的“返回 _refCount”行有未定义的行为。
    【解决方案2】:

    delete this 在析构函数中无效。它可以在其他地方使用。但这很少是一个好主意。 wxWidgets 框架将它用于他们的线程类。它有一种模式,当线程结束执行时,它会自动释放系统资源和自身(wxThread 对象)。我觉得这很烦人,因为从外面看,你不知道引用它是否有效——你不能再调用像IsValid 这样的函数,因为该对象不存在。这听起来像是delete this 的主要问题,除了它不能用于非动态对象的问题。

    如果您这样做,请确保您不要触摸任何数据成员,或在您以这种方式删除的对象上再调用任何成员函数。最好将其作为非虚拟、受保护或私有函数中的最后一条语句。调用 delete 在虚拟和/或公共函数中也是有效的,但我会限制这样做的方法的可见性。

    C++ FAQ 有一个关于此的条目。 C++ 标准引用我的上述声明 (3.8p5):

    在对象的生命周期开始之前但在对象将占用的存储空间已分配之后,或者在对象的生命周期结束之后并且在对象所占用的存储空间被重用或释放之前,任何指向该对象的指针可以使用对象将或曾经位于的存储位置,但只能以有限的方式使用。 [...] 如果对象将是或曾经是具有非平凡析构函数的类类型,并且指针用作删除表达式的操作数,则程序具有未定义的行为。

    当对象的析构函数开始执行时,生命周期结束。请注意,该段之后的规则有一些例外,用于构建和销毁的对象(例如,您可以访问非静态数据成员),详见12.7

    【讨论】:

      【解决方案3】:

      在早期的 C++ 时代,有充分的理由这样做。例如,引用计数对象的自我删除(如 JaredPar 所说)。 据我所知,从长远来看,它们都被认为是一个坏主意。

      【讨论】:

      • 正是我的想法。今天,如果我需要编写一个引用计数的对象,我会将数据保存在一个额外的对象中,并在引用计数降至零时使宿主对象(被复制的对象)删除包装的数据。自我删除气味:)
      • @Johannes Schaub - litb:完全同意;一个负责其职责并决定何时清理自己的对象?好恶心!
      • @JohannesSchaub-litb 然后宿主对象必须在完成后自行删除...
      【解决方案4】:

      在双向链表中,可以在不引用任何外部结构(例如高级“列表”对象)的情况下删除节点。这使得每个节点处理自己的释放是合理的(可能与互补的静态方法相结合,以处理来自同一内存池的初始分配)。在这种情况下,节点对象删除自身(当用户请求时)是有意义的。

      void RemoveAndDeallocate()
      {
          LinkedListNode *current_prev = prev, *current_next = next;
          current_prev->next = current_next;
          current_next->prev = current_prev;
          delete this;
      }
      

      虽然,从一个列表中取消链接并链接到另一个列表中的节点也是合理的,而不释放任何内存,因此单个删除操作无条件释放内存是不可取的。

      【讨论】:

        猜你喜欢
        • 2011-11-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-01-08
        • 2013-08-18
        • 2021-12-16
        相关资源
        最近更新 更多