28

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

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

还有其他情况可以使用此类语句吗?

4

4 回答 4

32

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

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

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

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

于 2009-01-15T16:16:04.123 回答
24

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

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

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

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

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

于 2009-01-15T16:44:55.627 回答
3

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

于 2009-01-15T17:06:34.427 回答
2

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

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

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

于 2010-01-30T02:20:19.723 回答