11

Please consider the following code:

class foo
{
public:
    foo(){}
    ~foo(){}
    void done() { delete this;}
private:
    int x;
};

What is happening (and is it valid?) in the following two options:

option 1:

void main()
{
   foo* a = new foo();
   a->done();
   delete a;
}

option 2:

void main()
{
   foo a;
   a.done();
}

Will the second delete a; statement at option 1 will cause an exception or heap corruption?

Will option2 cause an exception or heap corruption?

NirMH
  • 4,769
  • 3
  • 44
  • 69
  • Did you forget the opening brackets for the class by mistake or is it exactly the copy pasted code? – Neophile Jan 11 '12 at 13:46
  • Interesting. I'd guess the first would cause a segfault or heap corrupetion, and the second will do whatever deleting a pointer to the stack does. – cha0site Jan 11 '12 at 13:50
  • 2
    `void main()` is not valid C++. – Kerrek SB Jan 11 '12 at 14:08
  • See this: http://www.parashift.com/c++-faq-lite/freestore-mgmt.html#faq-16.15. Your first example violates #4, and your second example violates #1. – Fred Larson Jan 11 '12 at 14:24

7 Answers7

20

delete this; is allowed, it deletes the object.

Both your code snippets have undefined behavior - in the first case deleting an object that has already been deleted, and in the second case deleting an object with automatic storage duration.

Since behavior is undefined, the standard doesn't say whether they will cause an exception or heap corruption. For different implementations it could be either, neither, or both, and it may or may not be the same each time you run the code.

Steve Jessop
  • 273,490
  • 39
  • 460
  • 699
4

Both would cause an error.

The first pointer is deleted twice, with the second delete causing the error whereas the second one is allocated on the stack and cannot be implicitly deleted (error caused by first invocation of destructor).

Linus Kleen
  • 33,871
  • 11
  • 91
  • 99
  • I edited the question. I think it should be allocated on heap and then deleted with `done`. What's happening in this case? Deleting on stack doesn't make sense and probably not being asked by OP. – duedl0r Jan 11 '12 at 13:51
  • Your answer is correct, but the question was what *sort* of error would occur. – cha0site Jan 11 '12 at 13:52
  • @duedl0r That's an assumption made by *you*. I think the OP was intending just that. – Linus Kleen Jan 11 '12 at 13:52
  • Currently the OP's option 2 is `foo a; a.done();` This will call delete on a non free store pointer, and is therefore not correct. – bames53 Jan 11 '12 at 13:55
  • @LinusKleen: the OP asked whether this is correct: `foo a; a->done();` which is not correct in any interpretation. I fixed it so it would make sense the most. – duedl0r Jan 11 '12 at 13:57
  • @bames53: Sure, but option 1 is a double free, and also not correct. Therefore my assumption that this question is about C++'s failure modes. – cha0site Jan 11 '12 at 13:58
  • How do you know it will cause an error? Can you quote the standard? I believe it will be undefined behavior. – Luchian Grigore Jan 11 '12 at 13:58
  • @cha0site I was talking to Linus Kleen because his answer at that time stated that option 2 would be correct. Because the question and answer were both edited it appeared as though he was saying deleting a stack pointer was okay. – bames53 Jan 11 '12 at 14:04
3

This question has been answered but I will add a new point that if your class does call delete this then you should also make the destructor private.

This ensures that only the class can delete itself.

If you make your destructor private above, both of your code samples will fail to compile.

CashCow
  • 30,981
  • 5
  • 61
  • 92
  • of course it doesn't prevent all errors e.g. using the object after calling done() on it (even calling done() again will invoke a double delete). – CashCow Jan 11 '12 at 15:11
1

Both would cause an error, what you want is:

void main()
{
   foo* a = new foo();
   a->done();
}

Which the compiler will expand to something like below, which I hope makes deleting "this" a bit less confusing.

void __foo_done(foo* this)
{
   delete this;
}

void main()
{
   foo* a = new foo();
   __foo_done(a);
}

See also, Is it legal (and moral) for a member function to say delete this?

ronag
  • 49,529
  • 25
  • 126
  • 221
  • What if it is the first member of an object in a standard-layout (or POD) class, which was allocated with plain new, and which has no other destructors? (Not that that wouldn't be _insane_, but, well...) – Random832 Jan 11 '12 at 15:54
  • @Random832: I can't make sense of your question, sorry. – ronag Jan 11 '12 at 15:59
  • The FAQ question you link provides a list of conditions under which `delete this` is safe. Since the first member of a standard-layout class has the same address as the parent object itself, it seems like that would theoretically be another case. – Random832 Jan 11 '12 at 16:01
  • @Random832: It would work in the same way as the non `delete this` case. – ronag Jan 11 '12 at 16:09
1

Calling delete this is a bad idea. Whoever calls new should call the delete. Hence the problems as highlighted in the other responses.

Also you can have memory leaks/undefined behaviour when construcing an array of objects.

Ed Heal
  • 59,252
  • 17
  • 87
  • 127
  • Why is calling `delete this` a bad idea? I'd say that in many (most?) applications, it would be the most common form of `delete`. – James Kanze Jan 11 '12 at 14:19
  • @JamesKanze Why? `delete this` is not normal ways of releasing objects. – BЈовић Jan 11 '12 at 14:34
  • @VJovic That depends on the application. In a lot of applications, the most frequent (or even the only) `delete`s will be `delete this`. In others, the `delete` will systematically be in the transaction manager, or something similar. And in others... It depends on why you are using dynamic memory. If it for model objects, then `delete this` or a transaction manager are the most frequent. If it is for complex data structures of unknown size, then the owner of the structure will do the `delete`, and `delete this` will almost never occur. – James Kanze Jan 11 '12 at 15:43
  • 2
    @JamesKanze: I hope you're joking! There's almost no situation in which `delete this` is appropriate, as an object should never have to know or care about its own storage class. (Or I'd be very curious to see a legitimate use.) It would be a terrible mixup of responsibilities. – Kerrek SB Jan 11 '12 at 15:43
  • @KerrekSB I'm not joking. An object has a specific role in an application, and that determines how it is allocated. If the object manages its own lifetime (as one would expect of most "objects" in the OO sense), then it is the object which determines its own lifetime, either by using `delete this` or by registering itself for deletion with a transaction manager. – James Kanze Jan 11 '12 at 16:05
  • @JamesKanze In most applications, the most frequent `delete`s are handled by smart pointers. – Etienne de Martel Jan 11 '12 at 16:10
  • @JamesKanze: I'm sorry, I don't follow. How do objects "typically" manage their own lifetime? Do they just will themselves into existence? I've never seen an OO design that has self-managing objects. Typically there's a hierarchy of responsibility. – Kerrek SB Jan 11 '12 at 16:11
  • In a large system, objects can have complex and possibly asynchronous destruction/finalization processes. In such a case, it is usually best to tell the object that you are done using it, and let the object self-destruct after finalization. Objects that do not require extra time can self-destruct synchronously, but whether they do is an implementation detail and should not be exposed in the interface. COM's Add_Ref()/Release() is a prime example of this pattern. – Simon Richter Jan 11 '12 at 16:38
  • @EtiennedeMartel It depends on the application domain, but I've never seen an application where smart pointers could handle more than a small subset of the objects correctly. If you start using `shared_ptr` as a poor man's garbage collection, then you start having to add `dispose` functions everywhere, as you do in Java. – James Kanze Jan 11 '12 at 17:47
  • @KerrekSB The object is created in reaction to an external event (often by calling a static factory method in the class). After than, it reacts to external events which concern it. Depending on the application, those events may determine the object's lifetime. (Otherwise, the object generally belongs to *one* other object, which determines its lifetime. Still no smart pointers, though.) – James Kanze Jan 11 '12 at 17:50
0

In both cases your heap will get corrupted. Of course, you can't use in option 2 "->" if the left value (in this case, "a") is not a pointer, the correct form in option 2 would be a.done(); But yeah, you should get a heap corruption if you try to delete 1) what's been already deleted, or 2) local variable.

Calling "delete this" is technically valid and frees the memory.

EDIT I was curious and actually tried this:

class foo 
{
public: 
    foo(){} 
    ~foo(){} 
    void done() { delete this; } 
    void test() { x = 2; }
    int getx() { return x; }
private: 
    int x; 
} ;


int main(int argc, char* argv[])
{
    foo *a = new foo();
    a->done();
    a->test();
    int x = a->getx();
    printf("%i\n", x);
    return x;
}

A call to printf will succeed, and x will hold the value 2.

Dejan Janjušević
  • 3,181
  • 4
  • 41
  • 67
0

I would be very cautious about the context in which you free memory. Whilst calling "delete this;" will attempt to free the memory associated with the class structure, that operation has no means of deducing the context of the original memory allocation, ie, if it's allocated from the heap or the stack. My advise would be to rework your code so that the deallocation operation is invoked from an external context. Note that this is different from deallocating structures internal to the class, in that case, use the destructor.

Gearoid Murphy
  • 11,834
  • 17
  • 68
  • 86