278

Is it allowed to delete this; if the delete-statement is the last statement that will be executed on that instance of the class? Of course I'm sure that the object represented by the this-pointer is newly-created.

I'm thinking about something like this:

void SomeModule::doStuff()
{
    // in the controller, "this" object of SomeModule is the "current module"
    // now, if I want to switch over to a new Module, eg:

    controller->setWorkingModule(new OtherModule());

    // since the new "OtherModule" object will take the lead, 
    // I want to get rid of this "SomeModule" object:

    delete this;
}

Can I do this?

Flow
  • 23,572
  • 15
  • 99
  • 156
Martijn Courteaux
  • 67,591
  • 47
  • 198
  • 287
  • 16
    Main problem would be that if you `delete this` you have created a tight coupling between the class and the allocation method used for creating objects of that class. That is very poor OO design, since the most fundamental thing in OOP is to make autonomous classes which don't know or care about what their caller is doing. Thus a properly designed class shouldn't know or care about how it was allocated. If you for some reason need such a peculiar mechanism, I think a better design would be to use a wrapper class around the actual class, and let the wrapper deal with the allocation. – Lundin Oct 14 '15 at 07:58
  • Can't you delete in `setWorkingModule`? – Jimmy T. Apr 12 '20 at 10:35
  • @Lundin [CFrameWnd](https://learn.microsoft.com/en-us/cpp/mfc/reference/cframewnd-class?view=msvc-160) class from MFC does `delete this;` in `PostNcDestroy` because that's when the WinAPI class it's wrapping is getting destroyed presumably. So, it does have its own valid use cases, I'd say. – Aykhan Hagverdili Nov 29 '20 at 18:42
  • @Lundin The problem is not deallocation, but destruction. In C++ the only proper way to separate these two, and still achieve encapsulation and polymorphism, is to use shared_ptr. Unique_ptr does not separate them. The class in question doesn't care about allocation/deallocation, but it wants to control its lifetime. I would bet the class in question can be properly designed with shared_ptr/enable_shared_from_this, but I don't like that it has to be done that way, especially since shared_ptr/enable_shared_from_this eat a lot of code size and are therefore unusable for my embedded development. – Dragan Jul 16 '21 at 10:49

10 Answers10

271

The C++ FAQ Lite has a entry specifically for 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).

Maciej Szpakowski
  • 571
  • 1
  • 7
  • 22
JaredPar
  • 733,204
  • 149
  • 1,241
  • 1,454
  • 22
    The corresponding FQA also has some useful comment : http://yosefk.com/c++fqa/heap.html#fqa-16.15 – Alexandre C. Jun 30 '10 at 15:51
  • 3
    For safety you may use private destructor on the original object to make sure its not constructed on the stack or as a part of an array or vector. – Cem Kalyoncu Sep 29 '15 at 12:58
  • Define 'careful' – CinCout Sep 13 '17 at 12:24
  • 5
    'Careful' is defined in the linked FAQ article. (While the FQA link mostly rants - like almost everything in it - how bad C++ is) – CharonX May 03 '18 at 07:42
  • @CharonX • Yossi isn't programming in C++ anymore. He's much happier now. That's why the FQA has not been maintained against modern C++. I enjoy the FQA, because it's coming from a critical and unforgiving perspective at real pain points of C++ (albeit circa C++98) — something easy to ignore for those of us (myself included) who are acclimated or inculcated to those pain points. – Eljay Feb 13 '23 at 15:04
104

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. Over the years, many questions have been asked about what the standard says specifically about delete this;, as opposed to deleting some other pointer. The answer to that is fairly short and simple: it doesn't say much of anything. It just says that delete's operand must be an expression that designates a pointer to an object, or an array of objects. It goes into quite a bit of detail about things like how it figures out what (if any) deallocation function to call to release the memory, but the entire section on delete (§[expr.delete]) doesn't mention delete this; specifically at all. The section on destructors does mention delete this in one place (§[class.dtor]/13):

At the point of definition of a virtual destructor (including an implicit definition (15.8)), the non-array deallocation function is determined as if for the expression delete this appearing in a non-virtual destructor of the destructor’s class (see 8.3.5).

That tends to support the idea that the standard considers delete this; to be valid -- if it was invalid, its type wouldn't be meaningful. That's the only place the standard mentions delete this; at all, as far as I know.

Anyway, some consider delete this a nasty hack, and tell anybody who will listen that it should be avoided. One commonly cited problem is the difficulty of ensuring that objects of the class are only ever allocated dynamically. Others consider it a perfectly reasonable idiom, and use it all the time. Personally, I'm somewhere in the middle: I rarely use it, but don't hesitate to do so when it seems to be the right tool for the job.

The primary time you use this technique is with an object that has a life that's almost entirely its own. One example James Kanze has cited was a billing/tracking system he worked on for a phone company. When you start to make a phone call, something takes note of that and creates a phone_call object. From that point onward, the phone_call object handles the details of the phone call (making a connection when you dial, adding an entry to the database to say when the call started, possibly connect more people if you do a conference call, etc.) When the last people on the call hang up, the phone_call object does its final book-keeping (e.g., adds an entry to the database to say when you hung up, so they can compute how long your call was) and then destroys itself. The lifetime of the phone_call object is based on when the first person starts the call and when the last people leave the call -- from the viewpoint of the rest of the system, it's basically entirely arbitrary, so you can't tie it to any lexical scope in the code, or anything on that order.

For anybody who might care about how dependable this kind of coding can be: if you make a phone call to, from, or through almost any part of Europe, there's a pretty good chance that it's being handled (at least in part) by code that does exactly this.

atil
  • 41
  • 1
  • 5
Jerry Coffin
  • 476,176
  • 80
  • 629
  • 1,111
  • 2
    Thanks, I'll put it somewhere in my memory. I suppose you define the constructors and destructors as private and use some static factory method to create such objects. – Alexandre C. Jun 30 '10 at 18:47
  • @Alexandre: You'd probably do that in most cases anyway -- I don't know anywhere close to all the details of the system he was working on, so I can't say for sure about it though. – Jerry Coffin Jun 30 '10 at 20:27
  • The way I often get around the problem of how the memory was allocated is to include a `bool selfDelete` parameter in the constructor that gets assigned to a member variable. Granted, this means handing the programmer enough rope to tie a noose in it, but I find that preferable to memory leaks. – MBraedley Sep 14 '16 at 16:24
  • 1
    @MBraedley: I've done the same, but prefer to avoid what seems to me like a kludge. – Jerry Coffin Sep 14 '16 at 17:22
  • For anybody who might care ... there's a pretty good chance that it's being handled (at least in part) by code that does exactly `this`. Yes, the code is being handled by the exactly `this`. ;) – Galaxy Jan 07 '19 at 01:32
53

If it scares you, there's a perfectly legal hack:

void myclass::delete_me()
{
    std::unique_ptr<myclass> bye_bye(this);
}

I think delete this is idiomatic C++ though, and I only present this as a curiosity.

There is a case where this construct is actually useful - you can delete the object after throwing an exception that needs member data from the object. The object remains valid until after the throw takes place.

void myclass::throw_error()
{
    std::unique_ptr<myclass> bye_bye(this);
    throw std::runtime_exception(this->error_msg);
}

Note: if you're using a compiler older than C++11 you can use std::auto_ptr instead of std::unique_ptr, it will do the same thing.

Mark Ransom
  • 299,747
  • 42
  • 398
  • 622
  • I can't get this to compile using c++11, is there some special compiler options for it? Also does it not require a move of the this pointer? – Owl Mar 22 '17 at 12:19
  • @Owl not sure what you mean, it works for me: http://ideone.com/aavQUK. Creating a `unique_ptr` from *another* `unique_ptr` requires a move, but not from a raw pointer. Unless things changed in C++17? – Mark Ransom Mar 22 '17 at 15:40
  • Ahh C++14, that'll be why. I need to update my c++ on my dev box. I'll try again tonight on my recently emerged gentoo system! – Owl Mar 30 '17 at 14:49
  • It's a hack, unless you make your destructor private, which will prevent unique_ptr from working. – Dragan Jul 16 '21 at 10:54
27

One of the reasons that C++ was designed was to make it easy to reuse code. In general, C++ should be written so that it works whether the class is instantiated on the heap, in an array, or on the stack. "Delete this" is a very bad coding practice because it will only work if a single instance is defined on the heap; and there had better not be another delete statement, which is typically used by most developers to clean up the heap. Doing this also assumes that no maintenance programmer in the future will cure a falsely perceived memory leak by adding a delete statement.

Even if you know in advance that your current plan is to only allocate a single instance on the heap, what if some happy-go-lucky developer comes along in the future and decides to create an instance on the stack? Or, what if he cuts and pastes certain portions of the class to a new class that he intends to use on the stack? When the code reaches "delete this" it will go off and delete it, but then when the object goes out of scope, it will call the destructor. The destructor will then try to delete it again and then you are hosed. In the past, doing something like this would screw up not only the program but the operating system and the computer would need to be rebooted. In any case, this is highly NOT recommended and should almost always be avoided. I would have to be desperate, seriously plastered, or really hate the company I worked for to write code that did this.

Bob Bryan
  • 3,687
  • 1
  • 32
  • 45
  • 7
    +1. I can't understand why you were downvoted. "C++ should be written so that it works whether the class is instantiated on the heap, in an array, or on the stack" is very good advice. – Joh Sep 13 '12 at 11:31
  • 1
    You could just wrap the object you want to delete itself in a special class which deletes the object and then itself, and use this technique for preventing stack allocation: http://stackoverflow.com/questions/124880/is-it-possible-to-prevent-stack-allocation-of-an-object-and-only-allow-it-to-be There are times when there is really not a viable alternative. I just used this technique to self-delete a thread that is started by a DLL function, but the DLL function must return before the thread ends. – Felix Dombek Dec 04 '13 at 01:31
  • 1
    You can't program in such a way that someone doing just copy and paste with your code ends up misusing it anyway – Jimmy T. Apr 12 '20 at 10:45
24

It is allowed (just do not use the object after that), but I wouldn't write such code on practice. I think that delete this should appear only in functions that called release or Release and looks like: void release() { ref--; if (ref<1) delete this; }.

Kirill V. Lyadvinsky
  • 97,037
  • 24
  • 136
  • 212
21

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

void IMyInterface::Release()
{
    --instanceCount;
    if(instanceCount == 0)
        delete this;
}
UnknownGosu
  • 854
  • 6
  • 9
8

This is the core idiom for reference-counted objects.

Reference-counting is a strong form of deterministic garbage collection- it ensures objects manage their OWN lifetime instead of relying on 'smart' pointers, etc. to do it for them. The underlying object is only ever accessed via "Reference" smart pointers, designed so that the pointers increment and decrement a member integer (the reference count) in the actual object.

When the last reference drops off the stack or is deleted, the reference count will go to zero. Your object's default behavior will then be a call to "delete this" to garbage collect- the libraries I write provide a protected virtual "CountIsZero" call in the base class so that you can override this behavior for things like caching.

The key to making this safe is not allowing users access to the CONSTRUCTOR of the object in question (make it protected), but instead making them call some static member- the FACTORY- like "static Reference CreateT(...)". That way you KNOW for sure that they're always built with ordinary "new" and that no raw pointer is ever available, so "delete this" won't ever blow up.

Zack Yezek
  • 1,408
  • 20
  • 7
  • 1
    Why can't you just have a (singleton) class "allocator/garbage collector", an interface through which all allocation is done and let that class handle all reference counting of the allocated objects? Rather than forcing the objects themselves to bother with garbage collection tasks, something that is completely unrelated to their designated purpose. – Lundin Oct 14 '15 at 08:09
  • 1
    You can also just make the destructor protected to prohibit static and stack allocations of your object. – Game_Overture Jan 27 '17 at 15:05
7

You can do so. However, you can't assign to this. Thus the reason you state for doing this, "I want to change the view," seems very questionable. The better method, in my opinion, would be for the object that holds the view to replace that view.

Of course, you're using RAII objects and so you don't actually need to call delete at all...right?

Edward Strange
  • 40,307
  • 7
  • 73
  • 125
4

This is an old, answered, question, but @Alexandre asked "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.)

Bo Persson
  • 90,663
  • 31
  • 146
  • 203
Krazy Glew
  • 7,210
  • 2
  • 49
  • 62
0

Delete this is legal as long as object is in heap. You would need to require object to be heap only. The only way to do that is to make the destructor protected - this way delete may be called ONLY from class , so you would need a method that would ensure deletion

Swift - Friday Pie
  • 12,777
  • 2
  • 19
  • 42
  • 2
    Do note that making the dtor protected won't make sure the object is only ever created with `new` operator. It could be `malloc+operator new()` or some means, in which case `delete this;` would cause undefined behavior. – Aykhan Hagverdili Nov 29 '20 at 18:33
  • 1
    `auto foo = new Foo[1];` and now `delete this;` ought to be `delete[] this;`. And if there's an `auto foo = new Foo[2];` the `foo[1]` can't do a `delete[] this;` or `delete this;`. The point being, `delete this;` requires a level of discipline that the compiler won't help enforce if a mistake is made. A programmer can do it, they just have to be careful. – Eljay Jan 14 '23 at 14:18
  • @Eljay, which suggest that it may happen only in environment where such discipline is implemented. E.g. creation and deletion would be implemented in infrastructure in single place. – Swift - Friday Pie Jan 15 '23 at 00:18
  • @AyxanHaqverdili in case of placement-new any `delete` would be UB. Implied object creation because that would require access to destructor though to create temporal object. We have to give programmer at least some credit for sensibility if they use placement new. – Swift - Friday Pie Jan 15 '23 at 00:22