1

I know about the delete operator and how it automatically calls the destructor of a class. However, I've recently seen someone call the destructor of a class directly, which seemed quite strange to me. So I wrote short program that gives a really un-expected result:

#include <stdio.h>

class A
{
public:
  A()  {a = new int; *a=42; b=33;}
  ~A() {delete a;}

  int* a;
  int  b;
};

int main(int argc, const char ** argv)
{
  A* myA = new A();
  printf("a:%d  b:%d\n", *(myA->a), myA->b);
  myA->~A();
  printf("b:%d\n", myA->b);
  printf("a:%d\n", *(myA->a));
}

So as you see, I'm calling the destructor ~A(), so to my expectation the program should crash when trying to access the variable 'a' a second time (because it was deleted 2 lines ago). Instead.. the program just prints this without any complaints:

a:42  b:33
b:33
a:42

... Why? What happens exactly when I call ~A() directly? Is there any situation when it's useful to do so?

Wooble
  • 87,717
  • 12
  • 108
  • 131
OLL
  • 655
  • 5
  • 20
  • 5
    This is not surprising, if you break the rules, you don't get the results you expect. Don't break the rules and you won't have these problems. – David Schwartz Jan 08 '13 at 12:40
  • It doesn't have to crash. It can give the computer a break once in a while. – chris Jan 08 '13 at 12:40
  • 4
    C++ is not C. Do not use the [c] tag on questions about C++. – Wooble Jan 08 '13 at 12:41
  • 3
    Your question is basically "if this is undefined behaviour why doesn't it make my computer explode?" Please read http://c-faq.com/ansi/experiment.html – Jonathan Wakely Jan 08 '13 at 12:45
  • 2
    maybe because the pointer still points to the same memory address despite it was freed (that doesn't mean it was zeroed) ? – Davide Berra Jan 08 '13 at 12:49
  • ~A is just a function... You can call it, but all it does is execute the destructor. As you can see, even after calling the destructor, the object still exists in the 'owner scope' of main. The object is just a pointer in that scope, so even then it's not going to be deleted. No 'anarchic' pointers in C++ are handled even remotely automatically. You have to use objects. – ActiveTrayPrntrTagDataStrDrvr Jan 08 '13 at 12:52
  • On VC++ 2010 everytime it prints - a:-572662307 (or similar). And this is how it should be because delete a; is called in destructor. – SChepurin Jan 08 '13 at 13:03
  • check this http://www.parashift.com/c++-faq/dont-call-dtor-on-local.html – abnvp Jan 08 '13 at 13:04
  • Compare with destructor without delete - http://ideone.com/ART3jw – SChepurin Jan 08 '13 at 13:12
  • This is the best StackOverflow answer to this question: http://stackoverflow.com/questions/6441218/can-a-local-variables-memory-be-accessed-outside-its-scope – James Brock Jan 08 '13 at 13:44

4 Answers4

10

Calling the destructor manually is like calling a function - the code is executed, but the memory is not freed, as opposed to calling delete, when the memory is freed.

Accessing a after it was deleted will result in undefined behavior, and can appear to work.

Luchian Grigore
  • 253,575
  • 64
  • 457
  • 625
5

the program should crash when trying to access the variable 'a' a second time

It is an undefined behavior to access a deleted variable. This means that anything can happen, including program crashing.

What happens exactly when I call ~A() directly?

In your example nothing, because you do not delete that object, but you shouldn't do it.

Is there any situation when it's useful to do so?

Yes, the destructor should be explicitly be called for placement new, and that is the only case when the destructor should be called.

BЈовић
  • 62,405
  • 41
  • 173
  • 273
3

When you call ~A() directly, the code of the destructor is executed. This won't prevent the destructor from being called again ordinarily as it would by C++. Eg:

void func()
{
   A a;
   a.~A();  // calls destructor
   // Destructor runs again here as it always would.
}

In your example the memory for the int will be freed. That just means the runtime makes a note to say your program is no longer using the memory... but it doesn't necessarily mean the memory instantly gets wiped or used for something else. So, when you access the memory for the int later it still contains the same value. But, there is potential for some other thread to have reused this memory and something else could have overwritten it, but that just doesn't happen to be happening in your program.

A situation where it's useful to call ~A() directly is where you want to handle your own memory allocation for some situation you want to optimize. Eg, you may have your own string class and reserve a large pool of memory in one go. You can call the constructor and destructor manually to setup regions of memory in this pool to be properly initialized strings. You can do so without having to make any new allocations - just reuse the pool. But... I would say this is expert level programming and you need to know what you're doing and be doing it for a worthwhile performance gain.

Scott Langham
  • 58,735
  • 39
  • 131
  • 204
2

So as you see, I'm calling the destructor ~A(), so to my expectation the program should crash when trying to access the variable 'a' a second time (because it was deleted 2 lines ago). Instead.. the program just prints this without any complaints:

Not surprising. The code is buggy, as you note. So it's not going to do what you expect but something difficult to predict or understand. If you want code that behaves predictably, you have to follow the rules. That's what they're for.

"Somebody told me that in basketball you can't hold the ball and run. I got a basketball and tried it and it worked just fine. He obviously didn't understand basketball." -- Roger Miller

David Schwartz
  • 179,497
  • 17
  • 214
  • 278