tags:

views:

819

answers:

4

Today, I have seen some legacy code. In the destructor there is a statement like "delete this". I think, this call will be recursive. Why it is working?

I made some quick search on Y!, I found that if there is a need to restrict the user to create the stack object, we can make destructor private and provide an interface to delete the instance. In the interface provided, we have to call delete on this pointer.

Are there any other situations for using such statements?

+15  A: 

"delete this" is commonly used for ref counted objects. For a ref counted object the decision of when to delete is usually placed on the object itself. Here is an example of what a Release method would look like [1].

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

ATL COM objects are a prime example of this pattern.

[1] Yes I realize this is not thread safe.

JaredPar
While self-deletion of refcounted objects is a very common pattern, I think the original question was about putting it in a destructor, not a Release() function, in which case it's just insane.
rmeador
@rmeador, There are really two questions. Both the title and last sentence suggest wanting to know valid uses of "delete this;". I hope I answered that. The middle does suggest a question of "why delete this in a dtor". I agree to do so appears to be insane.
JaredPar
Your sample code has a bug. If _refCount is a member variable, when you "delete this" that member variable no longer exists, so your "return _refCount" line has undefined behaviour.
ChrisN
+9  A: 

delete this is not valid in a destructor. It can be used elsewhere. But it's only rarely a good idea (can't come up with any use-case directly). Doesn't mean i haven't seen it used though. The wxWidgets framework uses it for their thread class. It has a mode where, when the thread ends execution, it automatically frees system resources and itself (the wxThread object). I found it very annoying, because from outside, you can't know whether it's valid to refer it or not - you can't call a function like IsValid anymore, because the object doesn't exist. That smells like the main problem with delete this, apart from the problem that it can't be used for non-dynamic objects. The user of the object should control the lifetime of it, and not the object itself, because it didn't create itself too.

If you do it, make sure you don't touch any data-member, or call any member function anymore on the object you deleted that way. Best do it as the last statement in a non-virtual, protected or private function. Calling delete is valid in a virtual and/or public function too, but i would restrict the visibility of the method doing that.

The C++ FAQ has an entry about that. C++ Standard quote on my claim above (3.8p5):

Before the lifetime of an object has started but after the storage which the object will occupy has been allocated or, after the lifetime of an object has ended and before the storage which the object occupied is reused or released, any pointer that refers to the storage location where the object will be or was located may be used but only in limited ways. [...] If the object will be or was of a class type with a non-trivial destructor, and the pointer is used as the operand of a delete-expression, the program has undefined behavior.

Lifetime ends when the destructor of the object begins execution. Note there are exceptions to the rules coming after that paragraph for objects under construction and destruction (you are allowed to access non-static data members, for example), detailed at 12.7.

Johannes Schaub - litb
+2  A: 

There where considered to be good reasons to do this in the early C++ days. For example the self delete of a ref counted object (as JaredPar says). As far as I know they have all been found to be a bad idea in the long run.

David Allan Finch
exactly what i think. today if i would need to write a ref counted object, i would keep data in an extra object, and make the host object (the one that is copied around) delete the wrapped data when reference count drops to zero. self deleting smells :)
Johannes Schaub - litb
@Johannes Schaub - litb: Completely agree; an object responsible for its responsibilities and deciding when to clean itself up? Yucky!
Jason
A: 

In a doubly-linked list, it's possible to remove a node without referencing any outside structure, such as the high-level "list" object. This makes it reasonable for each node to handle its own deallocation (potentially coupled with a complementary static method to handle the initial allocation from the same pool of memory). In this situation, it could make sense for the node object to delete itself (when requested by the user).

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

Although, it's also reasonable for a node to be unlinked from one list and linked into another list, without deallocating any memory, so it's not desirable for a single remove operation to unconditionally free the memory.

Matthew