R@M3$H.NBlog

Delete this

02 October, 2013 - 6 min read

delete this is legal and does what you would expect: it calls your class's destructor and free the underlying memory. After delete this returns, your this pointer value does not change, so it is now a dangling pointer that should not be dereferenced. That includes implicit dereferencing using the class's member variables.

It is usually found in reference-counted classes that, when the ref-count is decremented to 0, theDecrementRefCount()/Release()/whatever member function calls delete this.

delete this is typically considered very bad form for many reasons. It is easy to accidentally access member variables after delete this. Caller code might not realize your object has self-destructed.

Also, delete this is a "code smell" that your code might not have a symmetric strategy for object ownership (who allocates and who deletes).

 

It is risky for one additional reason that hasn't been mentioned yet - you are assuming that the object has been allocated on the heap. This can be difficult to guarantee, although in the case of reference counting implementations isn't generally a problem.

 

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

Here's how I define "careful":

  1. You must be absolutely 100% positively sure that this object was allocated via new (not by new[], nor by [None](http://www.parashift.com/c++-faq-lite/placement-new.html "[11.10] What is "placement new" and why would I use it?"), nor a local object on the stack, nor a global, nor a member of another object; but by plain ordinarynew).
  2. You must be absolutely 100% positively sure that your member function will be the last member function invoked on this object.
  3. 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).
  4. 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.

Naturally the usual caveats apply in cases where your this pointer is a pointer to a base class when you don't have a virtual destructor.

 

Yes, delete this; has defined results, as long as (as you've noted) you assure the object was allocated dynamically, and (of course) never attempt to use the object after it's destroyed.

 

Well, in Component Object Model (COM) delete this construction can be a part of Releasemethod that is called whenever you want to release aquisited object:

void IMyInterface::Release()
{
    --instanceCount;
    if(instanceCount == 0)
        delete this;
}

   

Why would anyone want to do this?", and I thought that I might provide an example usage that I am considering this afternoon.

Legacy code. Uses naked pointers Obj*obj with a delete obj at the end.

Unfortunately I need sometimes, not often, to keep the object alive longer.

I am considering making it a reference counted smart pointer. But there would be lots of code to change, if I was to use ref_cnt_ptr<Obj> everywhere. And if you mix naked Obj* and ref_cnt_ptr, you can get the object implicitly deleted when the last ref_cnt_ptr goes away, even though there are Obj* still alive.

So I am thinking about creating an explicit_delete_ref_cnt_ptr. I.e. a reference counted pointer where the delete is only done in an explicit delete routine. Using it in the one place where the existing code knows the lifetime of the object, as well as in my new code that keeps the object alive longer.

Incrementing and decrementing the reference count as explicit_delete_ref_cnt_ptr get manipulated.

But NOT freeing when the reference count is seen to be zero in the explicit_delete_ref_cnt_ptr destructor.

Only freeing when the reference count is seen to be zero in an explicit delete-like operation. E.g. in something like:

template<typename T> class explicit_delete_ref_cnt_ptr { 
 private: 
   T* ptr;
   int rc;
   ...
 public: 
   void delete_if_rc0() {
      if( this->ptr ) {
        this->rc--;
        if( this->rc == 0 ) {
           delete this->ptr;
        }
        this->ptr = 0;
      }
    }
 };

OK, something like that. It's a bit unusual to have a reference counted pointer type not automatically delete the object pointed to in the rc'ed ptr destructor. But it seems like this might make mixing naked pointers and rc'ed pointers a bit safer.

But so far no need for delete this.

But then it occurred to me: if the object pointed to, the pointee, knows that it is being reference counted, e.g. if the count is inside the object (or in some other table), then the routine delete_if_rc0 could be a method of the pointee object, not the (smart) pointer.

class Pointee { 
 private: 
   int rc;
   ...
 public: 
   void delete_if_rc0() {
        this->rc--;
        if( this->rc == 0 ) {
           delete this;
        }
      }
    }
 };

Actually, it doesn't need to be a member method at all, but could be a free function:

map<void*,int> keepalive_map;
template<typename T>
void delete_if_rc0(T*ptr) {
        void* tptr = (void*)ptr;
        if( keepalive_map[tptr] == 1 ) {
           delete ptr;
        }
};

(BTW, I know the code is not quite right - it becomes less readable if I add all the details, so I am leaving it like this.)

 

Ideally delete operator should not be used for this pointer. However, if used, then following points must be considered.

1) delete operator works only for objects allocated using operator new (See http://geeksforgeeks.org/?p=8539). If the object is created using new, then we can do delete this, otherwise behavior is undefined.

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();
  getchar();
  return 0;
}
  1. Once delete this is done, any member of the deleted object should not be accessed after deletion.
#include<iostream>
using namespace std;
class A
{
  int x;
  public:
    A() { x = 0;}
    void fun() {
      delete this;
      /* Invalid: Undefined Behavior */
      cout<<x;
    }
};

 

The best thing is to not do delete this at all.

Thanks to Shekhu for providing above details.

References:
https://www.securecoding.cert.org/confluence/display/cplusplus/OOP05-CPP.+Avoid+deleting+this
http://en.wikipedia.org/wiki/This_%28computer_science%29

 

END