Should "Delete This" Be Called from Within a Member Method

Should delete this be called from within a member method?

Normally this is a bad idea, but it's occasionally useful.

It's perfectly safe as long as you don't use any member variables after you delete, and as long as clients calling this method understand it may delete the object.

A good example of when this is useful is if your class employs reference counting:

void Ref() {
m_References++;
}

void Deref() {
m_References--;
if (m_References == 0) {
delete this;
}
}

what will happen if you do delete this; in a member function?

This C++ FAQ entry answers this quite nicely, repeating here:

As long as you're careful, it's OK for an object to delete this.

Here's how I define "careful":

  • You must be absolutely 100% positively sure that this object was allocated via new (not by new[], nor by placement new, nor a local object on the stack, nor a global, nor a member of another object; but by plain ordinary new).
  • You must be absolutely 100% positively sure that your member function will be the last member function invoked on this object.
  • You must be absolutely 100% positively sure that the rest of your member function (after the delete this line) doesn't touch any piece of this object (including calling any other member functions or touching any data members).
  • You must be absolutely 100% positively sure that no one even touches the this pointer itself after the delete this line. In other words, you must not examine it, compare it with another pointer, compare it with NULL, print it, cast it, do anything with it.

You are violating the #3 by accessing pi after delete this

Is is safe to `delete this` in a virtual member function?

Yes, so long as you don't use this afterwards, and neither does anyone else with a pointer to *this, and this was guaranteed to be allocated by new as exactly the type you are deleting it as, or possessing a virtual destructor. (ie, never as a member of another object, in a std::vector, as an automatic storage variable, as a static variable, as a temporary, not new[], not placement new, etc etc etc)

This includes calling non-virtual methods, virtual methods, member access, calling dtors, and a myriad of other things; almost anything other than return; on the next line and somehow every other pointer to *this being cleaned up before you delete this; (or deterministically never being used).

As a general rule, the level of control you have to have over your objects lifetime is so great to make delete this; safe that you can refactor the lifetime management to be external to the class and in a smart resource owner, which maybe maintains its state as a pImpl which it deletes. c++ adores value types, and a type that delete this; can never be treated as a value.

There is nothing in the standard that makes delete this; extra dangerous for virtual objects, other than the higher tendency to inherit.

All types that delete this; should have either a virtual destructor or be final to avoid inheritance issues.

How can we call delete this; in a const-member function?

The const qualifier applied to a method have the effect of making the this passed to it a const pointer; in particular, in your case it will be a const UPNumber *.

Still, this is not a problem for delete: actually you can use delete on a const pointer without having to cast anything, as specified at §5.3.5 ¶2:

[Note: a pointer to a const type can be the operand of a delete-expression; it is not necessary to cast away the constness (5.2.11) of the pointer expression before it is used as the operand of the delete-expression. ]

Notice that, before the standard was completed, there have been many discussion about whether this was or wasn't a good idea, so some pre-standard compilers will issue an error when trying to delete const pointers.

The idea behind allowing this behavior is that otherwise you would have no way to delete const objects without using a const_cast; see this question for more info.

Usefulness of 'delete this' in member function

Generally speaking, it's a bad idea as you're technically inside a member function when you do it and suddenly every member of that class is now invalid. Obviously if you do not touch anything after the delete this; call, you'll be okay. But it's very easy to forget these things, try and access a member variable and get undefined behavior and spend time at the debugger.

That said, it's used in things like Microsoft's Component Object Model (COM), when releasing a component (NOTE, this isn't exactly what they do as CashCow points out and is for illustrative purposes only):

void AddRef() { m_nRefs++; }
void Release()
{
m_nRefs--;
if(m_nRefs == 0)
delete this;
// class member-variables now deallocated, accessing them is undefined behaviour!
} // eo Release

That said, in C++ we have smart pointers (such as boost::shared_ptr) to manage the lifetimes of objects for us. Given that COM is inter-process and accessible from languages such as VB, smart pointers were not an option for the design team.

Is delete this allowed in C++?

The C++ FAQ Lite has a entry specifically for this

  • https://isocpp.org/wiki/faq/freestore-mgmt#delete-this

I think this quote sums it up nicely

As long as you're careful, it's OK for an object to commit suicide (delete this).

Should destructor be called on member objects

For the first question yes. You can check the Qt docs here
where it is stated clearly:

QObjects organize themselves in object trees. When you create a
QObject with another object as parent, the object will automatically
add itself to the parent's children() list. The parent takes ownership
of the object; i.e., it will automatically delete its children in its
destructor. You can look for an object by name and optionally type
using findChild() or findChildren().

For the second question, the answer deserves a little bit more of explanation. If you have QObject pointers members that are not children of your object, you have to handle their disposal manually in the destructor of your class.

You can in theory use delete on any QObject* to invoke its destructor, but since Qt objects have a powerfull event system based on signals/slots, you must be aware of the interactions with event loops. If you brutally delete a QObject connected to another QObject while the latter one is still processing a signal coming from the first one, you may end up with some problems.

This holds in both mono and multi-threaded applications. You should therefore avoid the use of delete in favor of QObject::deleteLater() that will defer the deletion of the QObject until all the signal/slots related to it have been processed.

Lastly, in the context of the implementation of a destructor it doesn't really matter if you set the pointer to null, because it will be unavailable for further use anyway. It may be important if you delete the pointee in some other method, while your instance is still alive, and you set the pointer to null to flag it as uninitialized.



Related Topics



Leave a reply



Submit