4
int main()
{
    Class_Name t;
    Class_Name * p = &t;

    delete p;
    return 0;
}  

This code executes fine with 2 destructors being called? How does delete work with stack objects? Is the behavior undefined?

AliciaBytes
  • 7,300
  • 6
  • 36
  • 47
sk patra
  • 159
  • 4
  • The compiler takes care of everything – James Feb 04 '14 at 07:30
  • 4
    You really, really must not do this. Only use delete with new. The behaviour is undefined (see answer below) and eventually it will bite you. Stop it now. – david.pfx Feb 04 '14 at 11:08

1 Answers1

11

You're running into undefined behavior.

Standard (N3690) 5.3.5[expr.delete]/2

If the operand has a class type, the operand is converted to a pointer type by calling the above-mentioned conversion function, and the converted operand is used in place of the original operand for the remainder of this section. In the first alternative (delete object), the value of the operand of delete may be a null pointer value, a pointer to a non-array object created by a previous new-expression, or a pointer to a subobject (1.8) representing a base class of such an object (Clause 10). If not, the behavior is undefined.
...

You don't have a null pointer, nor do you have an Object previously allocated with new, so the behavior is undefined.

Note: Even when trying to do

int main()
{
    Class_Name t;
    t.~Class_Name()
    return 0;
}

it would be undefined behavior. Even though it doesn't have a delete in it, simply because it explicitly calls the destructor of an Object with automatic storage duration. Which means that the destructor would be called twice, once when calling it explicitly, the 2nd time when leaving it's scope.

Standard 12.4[class.dtor]/15

Once a destructor is invoked for an object, the object no longer exists; the behavior is undefined if the destructor is invoked for an object whose lifetime has ended (3.8). [ Example: if the destructor for an automatic object is explicitly invoked, and the block is subsequently left in a manner that would ordinarily invoke implicit destruction of the object, the behavior is undefined. —end example ]

Most of the time trying to do anything like that would (hopefully) lead to a crash. With a trivial deconstructor you might have (bad) luck and nothing happens though.

Little terminology nitpick here: The C++ standard doesn't talk about stack vs heap objects, it always talks about automatic vs dynamic storage duration respectively. As you can also see in the above quote.


You should always follow the general guideline:

  • For stack allocated objects don't do any explicit freeing/deleting (destructors get called automatically).
  • For each new there should be a corresponding delete
  • For each new[] there should be a corresponding delete[]
  • For each malloc or calloc there should be a corresponding free
AliciaBytes
  • 7,300
  • 6
  • 36
  • 47
  • The 1st paragraph is irrelevant. He is passing a pointer to an object. – BЈовић Feb 04 '14 at 07:54
  • 6
    @BЈовић It explicitly says that only null pointers and pointers to previosly with `new` allocated objects are valid, and everything else is invalid. Hence a pointer to an object on the stack is invalid for a delete expression. – AliciaBytes Feb 04 '14 at 07:57
  • Also note the subobject/base class in that clause is written a bit confusing but basically means you can call delete on a pointer to base class, which is pointing to an Element of a derived class. – AliciaBytes Feb 04 '14 at 08:00
  • 2
    @Tribse: It however should be added that for the subobject/base clause to work, the base has to have virtual destructor. It's a different clause in the specification that requires that, but the crash will actually come from the delete which won't be able to find where the object actually begins. – Jan Hudec Feb 04 '14 at 08:09
  • @JanHudec yes, guess I should have added that in my comment. =) – AliciaBytes Feb 04 '14 at 08:11