“删除这个”是否安全?

在我最初的基本testing中,这样做是完全安全的。 然而,它让我感到试图稍后在一个delete s的函数中操作thisthis可能是一个运行时错误。 这是真的, delete this它通常是安全的吗? 还是只有某些情况下是安全的?

delete this是合法的,做你所期望的:它调用你的类的析构函数,并释放底层的内存。 delete this返回之后,你的this指针值不会改变,所以它现在是一个悬挂的指针,不应该被解除引用。 这包括使用类的成员variables的隐式解引用。

它通常在引用计数的类中find,当ref-count递减到0时, DecrementRefCount() / Release() /任何成员函数调用都会delete this

delete this通常被认为是非常糟糕的forms,原因很多。 delete this后很容易意外地访问成员variables。 调用者代码可能不会意识到你的对象已经自毁。

此外, delete this是一个“代码味道”,您的代码可能没有对象所有权的对称策略(谁分配和谁删除)。 一个对象不能自己分配new ,所以调用delete this意味着类A正在分配一个对象,但类B后来释放它[自我]。

只要基本上是方法中的最后一个操作,删除“this”是安全的。 事实上,有几个专业级的API可以这样做(例如ATL的CComObject实现)。

调用“删除这个”之后,唯一的危险是试图访问任何其他的成员数据。 这当然是不安全的。

但不要在析构函数中做!

删除这是完全合法的,正如其他人已经提到的。 还有一个还没有提到的理由是有风险的 – 你假设这个对象已经被分配到了堆上。 这可能难以保证,尽pipe在引用计数的情况下实现通常不是问题。

正如其他人所说,删除这是一个有效的习惯用法,但为了安全起见,您必须确保该对象永远不会在堆栈上实例化。

一种方法是使构造函数和析构函数都是私有的,并通过类工厂函数来强制对象创build,该函数在堆上创build对象并返回指向它的指针。 类工厂可以是静态成员函数或朋友函数。 然后可以通过删除()方法来完成清除操作。 COM对象基本上以这种方式工作,除了它们引用计数与引用计数递减到零时发生的“删除这个”。

是。 这应该是完美的。 “这个”只是一个指针。 任何指针都会删除。 有关如何删除对象的信息包含在堆logging中。 这是如何通常在COM对象中实现IUnknown :: Release()。

删除这可能会导致一个问题,当你有你正在删除的对象的子类。 记得从上往下施工开始,从下往上开始删除。 所以如果删除这个在层次结构中间,你基本上就失去了这个特定类下的所有对象。

当你正在实现一个引用计数对象时,删除这个方法非常方便,其中的一个例子就是COM类。

阅读一个类似的讨论。 您的理解是正确的,因为它确实起作用,是需要的,并且可能是危险的,因为之后您无法访问。

法律是的
安全号码

使用delete this被认为是不好的做法

但是,如果使用,必须考虑以下几点:

1. delete操作符仅适用于使用new操作符分配的对象。 如果对象是使用new创build的,那么我们可以delete this ,否则行为是不确定的。

 class A { public: void fun(){ delete this; } }; int main(){ /* Following is valid */ A *ptr = new A; ptr->fun(); ptr = NULL // make ptr NULL to make sure that things are not accessed using ptr. /* And following is invalid: Undefined Behavior */ A a; a.fun(); return 0; } 

2.一旦delete this完成,被删除对象的任何成员在删除后都不应该被访问。

  class A { int x; public: A() { x = 0; } void fun() { delete this; /* Invalid: Undefined Behavior */ cout<<x; } }; 

如果你从一个基类inheritance,并且在基类函数中删除了这个,那么使用派生类的指针会导致崩溃。 例如:

 class Base { virtual void Release() { delete this; } } class Derived : public Base { void Foo() { ... } } main() { Base *ptrDerived = new Derived(); ptrDerived->release(); ptrDerived->Foo() //Crash } 
Interesting Posts