“删除这个”是否安全?
在我最初的基本testing中,这样做是完全安全的。 然而,它让我感到试图稍后在一个delete
s的函数中操作this
, this
可能是一个运行时错误。 这是真的, 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 }