23

I was experimenting with destructors in C++ with this piece of code:

#include <iostream>

struct temp
{
    ~temp() { std::cout << "Hello!" << std::endl; }
};

int main()
{
    temp t;
    t.~temp();
}

I see that "Hello!" is being printed twice. Shouldn't the calling of the destructor free the object and the destructor shouldn't be called again when it goes out of scope? Or is there some other concept?

(I do not intend to do this in practice. I'm just trying to understand what's going on here.)

Baum mit Augen
  • 49,044
  • 25
  • 144
  • 182
Cygnus
  • 3,222
  • 9
  • 35
  • 65
  • 2
    You are not supposed to call the destructor manually PERIOD. It is automatically called when objects go out of scope or when they are deleted if dynamic memory allocation is being used. – dtech Aug 09 '12 at 14:19
  • 17
    @ddriver: There is one exception: if you allocate an object using [placement new](http://en.wikipedia.org/wiki/Placement_syntax), then you must invoke its destructor manually. – Jason R Aug 09 '12 at 22:25
  • 7
    @ddriver: Less harsh pls. – Sebastian Mach Aug 13 '12 at 12:58
  • 1
    @phresnel - what's harsh about my post? Any particular word, or just the way you decide to interpret and voice it it in your mind? ;) – dtech Aug 13 '12 at 14:13
  • 4
    @ddriver: I think I am not alone looking at all-upper words like `PERIOD` as a way to express anger or frustration in an unhelpful tone. It's not like the questioner is insisting on doing this, just asking why. – Sebastian Mach Aug 13 '12 at 14:18
  • 1
    @phresnel - capitalization is merely a way to accent a word. Anger or frustration is merely the way your mind chooses to interpret that accent, for some reason. It is a wrong interpretation, since I don't recall being angry or frustrated when I wrote that comment, and even if I was I wouldn't allow it to color to my statement. You are most likely confusing the capitalization of a certain word with the morons, who "shout" by writing in all in caps. Point is, the problem is in your receiver, expand your horizons a bit, there are many flavors of and many motivations for capitalization. – dtech Aug 15 '12 at 09:19
  • 2
    @ddriver: Surely it is about my mind. But why was that "PERIOD" needed at all? Even without the caps, it does look harsh to me, and I remind a friend of mine talking to me about the exact same topic some years ago. It is a bit like when you say to your child "Because it is like it is, period.", which is all but an explanation (and in this case even incorrekt or incomplet at best). – Sebastian Mach Aug 15 '12 at 09:27
  • @phresnel - because it must be stressed that it is a bad practice to call destructors manually, resulting in potential issues. Unless the case of using `placement new` as Jason noted. Except this case, the normal programming flow is for destructors to be called automatically, either by the `delete` operator or when objects all out of scope. I think it is clear I didn't use it in the "Because it is like it is, period." i.e. dogmatic/granted context. – dtech Aug 15 '12 at 09:40
  • 1
    @ddriver: Up to the PERIOD, you did. And many things must be stressed, esp. in C++. Many PERIODs wait to be summoned then. – Sebastian Mach Aug 15 '12 at 09:47

10 Answers10

44

It happens because you told it to happen. The destructor for an automatic variable is always called when the variable goes out of scope. You also called it. That's two calls total.

Calling an object's destructor does not signal to C++ not to call it again, since in normal execution there is no need to keep track.

The solution is to never manually call your destructor.

Jonathan Grynspan
  • 43,286
  • 8
  • 74
  • 104
  • OK. But when i call it the first time, shouldnt it deallocate the object and the second call should lead to a seg fault ? – Cygnus Aug 09 '12 at 13:13
  • 7
    No. The object is *automatic*, not *dynamic*. This means it isn't allocated in a place that can be deallocated (on most systems, it goes on the stack instead of the heap.) Since your object is automatically allocated and has no dynamically allocated fields, it is still fully-formed at the end of its scope. This is highly implementation-specific behaviour and must never be relied upon. – Jonathan Grynspan Aug 09 '12 at 13:16
  • 3
    @Cygnus: It results in undefined behavior. – GManNickG Aug 09 '12 at 13:49
  • GManNickG: Is it really UB? I could imagine a weird design pattern using destructors for functions that need to be called 1 or more times per instance, without having to add a helper function. – Inverse Aug 09 '12 at 21:40
  • 8
    @Inverse: Yes, according to [C++03 12.4/14](http://cs.nyu.edu/courses/summer12/CSCI-GA.2110-001/downloads/C++%20Standard%202003.pdf): `the behaviour is undefined if the destructor is invoked for an object whose lifetime has ended`. Formally speaking, calling the destructor (either manually or automatically) indicates end-of-life. – Justin ᚅᚔᚈᚄᚒᚔ Aug 09 '12 at 21:58
  • You might want to add a note on the placement new-syntax, as Jason R suggested in one of the questions comments. When using placement new, you _must_ call the destructor manually (or at least you should). I guess this is the reason why it's even possible to do it at all. – Excelcius Aug 11 '12 at 08:37
  • 1
    @Excelcius: That would be encouraging the OP to use placement new. :P – Jonathan Grynspan Aug 11 '12 at 12:25
  • You're probably right, I just wanted to point out that _never_ calling the destructor is not always the way to go (but in this and most other cases, of course, it is). – Excelcius Aug 11 '12 at 19:22
  • Old answer, but good. Can you fold @Justinᚅᚔᚈᚄᚒᚔ comment about how it is not just ill advised, but undefined behavior, when you do what the OP did into your answer? – Yakk - Adam Nevraumont Nov 30 '14 at 01:56
20

Calling the destructor does not free the object.

The destructor is there to clean up the internals of the object and then the object itsself is freed after the destructor finishes.

It's an error to do what you are doing similarly to the way that you can call delete twice on an object but it's an error to do so.

There are only a very few cases where you want to call the destructor manually and this isn't one of them. It's really there for the times you manually construct an object at a memory location using placement new and then need to be able to destruct it without freeing the memory.

jcoder
  • 29,554
  • 19
  • 87
  • 130
3

I see that "Hello!" is being printed twice. shouldn't the calling of the destructor free the object and the destructor shouldn't be called again when it goes out of scope. Or is there some other concept ?

That's correct.

I must mention that im not intending to do this in practice. Im just trying to understand whats going on here.

You've called the destructor, preparing an object to be destroyed. But this is also done automatically when an object goes out of scope, before it's actually de-allocated.

The thing to understand is this: If you do things that don't make sense, then bad things happen. So don't do things that don't make sense. If you manually call a destructor, the descructor runs. That has no effect on anything else unless the destructor actually does something that has an effect.

David Schwartz
  • 179,497
  • 17
  • 214
  • 278
  • Haha. Thats right !! As i said, this is something that just came in my mind !! But yrah - "dont do things that dont make sense" !! :) – Cygnus Aug 09 '12 at 13:20
  • 5
    It also shows another programming maxim -- broken code is harder to understand than correct code. – David Schwartz Aug 09 '12 at 13:21
  • David, you said "The code's broken. It destroys an object while it's still in scope. So it's still in scope but no longer exists. Ouch.". But the code is not "destroying" the object when he manually calls the destructor. He's just calling a function (and making the incorrect assumption it's being destroyed.) It's not destroyed, it still exists. Calling the destructor is not a great practice, to be sure, but it's not illegal nor even always incorrect. – John Deters Aug 09 '12 at 20:54
  • 2
    _"shouldn't the calling of the destructor free the object and the destructor shouldn't be called again when it goes out of scope."_ [...] _"That's correct"_ Am I misreading this? It seems entirely incorrect to me. Maybe the destructor _"shouldn't"_ be called again when it goes out of scope in the OP's view, but it _will_ be called again because the language guarantees it. – Jonathan Wakely Nov 29 '14 at 20:17
  • @JonathanWakely The calling of the destructor should free the object (because he wants the object to be destroyed and freed at the same time) and the destructor shouldn't be called again when it goes out of scope (because if it's called when it goes out of scope, that's the only time it should be called). His code forces behavior other than that, which is why it's broken. – David Schwartz Nov 29 '14 at 22:31
  • 1
    OK, I think we're agreeing but at least one of us is misinterpreting what the OP meant :) I read the text I quoted from the OP as saying "I believe that explicitly calling the destructor frees the object, and that means the destructor won't be called again" ... which is why I was surprised when you said that was correct. – Jonathan Wakely Nov 30 '14 at 01:42
1

Destructor is meant to be called when an object goes out of scope if the object is in the stack as in this case or called when it is explicitly destructed with delete when the object is created on the heap with new operator at the first place.

There is no way for the compiler or the run time system to keep track whether the destructor is called by you manually or not. Also it is a very bad practice to make a call to the destructor.

If you want to do some manual cleaning (other than the object being deleted from memory or getting removed from the stack) before the object getting deleted you may do something like this.

Here you want to allow the client to manually clean things, even before the object gets deleted. But in addition to that, you clean things if client misses to clean it.

class A
{
public:
    A() : _closed(false)
    {}

    ~A()
    {
        close();
    }

    void close()
    {
        if (! _closed()) {
            // close file handles etc.
        }
    }

private:
    bool _closed
}
Senthil Babu
  • 1,243
  • 2
  • 11
  • 20
  • 2
    It would absolutely be possible for the run-time to keep track of manual destructor-invocations - but it would be against the [zero-overhead principle](http://en.wikipedia.org/wiki/C%2B%2B#Philosophy) of C++. – Björn Pollex Aug 09 '12 at 13:20
1

You just call the destructor, you don't actually free any memory (it is statically allocated). If you use new and then delete the destructor will only be called once.

simmmons
  • 211
  • 1
  • 4
1

The destructor is not the "destroyer" of the object. It's just an ordinary function, but it's called automatically by the language immediately prior to the time of destruction.

It's official name is the destructor, but perhaps it would be more easily understood if we called it the "Before-Destruction" function.

John Deters
  • 4,295
  • 25
  • 41
  • 1
    I strongly disagree with this answer. Destruction is, by definition, the process of running the destructor, not something that happens afterwards. The standard says the object's lifetime ends when the destructor call _starts_. After the destructor finishes nothing else happens, so if that's "before destruction" then what are you suggesting is "destruction"? What is "the time of destruction"? Going out of scope? Something else? I think it makes much more sense to use the word "destruction" to denote what the destructor does, and use some other term for whatever it is you're referring to. – Jonathan Wakely Nov 29 '14 at 20:09
1

You won't need to call to a destructor, although it is possible to do so. The compiler should implicitly run your destructor for you when an object is no longer used. When objects are created, your constructor is utilized for that object, if it has been declared with specific and initialized values for your class members. When you no longer need your object your destructor will run and delete member variable declarations and their values. This is most useful for languages that don't utilize automatic garbage collection, like C++.

SuperS7
  • 41
  • 1
0

You shouldn't actually call the deconstructor. It is called for you by the runtime support. Hence your calling it once and the runtime support is calling it the second time.

Here is some food for thought on destructors:

http://publib.boulder.ibm.com/infocenter/comphelp/v8v101/index.jsp?topic=%2Fcom.ibm.xlcpp8a.doc%2Flanguage%2Fref%2Fcplr380.htm

You can explicitly call deconstructors, however it's not recommended, normally they are implicitly called.

Brandon
  • 191
  • 2
  • 15
  • Technically, it's the runtime support (not the compiler) that calls the deconstructor ;) –  Aug 09 '12 at 18:28
0

You don't call the destructor explicitly, it is called automatically when the variable goes out of scope (here after the return 0; statement). That's why it is called twice, you call it, and then the system calls it.

If you want to be able to remove an instance of this class yourself, explicitly, you need to dynamically allocate it:

temp *t = new temp;     
// do stuff with t...
delete t;    // do not forget this, or the constructor is not being called at all
Björn Pollex
  • 75,346
  • 28
  • 201
  • 283
SvenS
  • 795
  • 7
  • 15
  • This is not a very good code-example. `t` should be initialized when it is declared. There is no need to check for `0` after `new`, because by default it would throw an exception if it could not create the object. Also, there is no need to set `t = NULL` after the `delete` - this is [usually a code-smell](http://stackoverflow.com/a/1931145/160206). – Björn Pollex Aug 09 '12 at 13:25
  • Well, t is being initialized when calling new. I could have done the initialization in the same line as the declaration, but I wanted to keep it simple. As for the pointers, you're welcome to edit the sample to incorporate advanced paradigms, but I don't know if that will help the op ;) – SvenS Aug 09 '12 at 14:12
0

The destructor of a class could be invoked:

  1. Explicitly

    When the destructor is explicitly invoked using the object of the class, the same way you invoke another member function of the class.

  2. Implicitly

    When the object of the class goes out of scope or an object which is created using the new operator is destroyed using the delete operator.

In your sample program, you do both

int main()
{
  temp t;

  t.~temp(); //1. Calling destructor explictly using the object `t`

  return 0;
} // 2. object `t` goes out of scope. So destructor invoked implictly

and that is the reason why you see the destructor being called twice.

As you have aptly thought, the destructor will destroy the resources which were created by constructor. So the destrutor should not be called explicitly, as it will result in destroying the already destroyed resource and that could be fatal.

nitin_cherian
  • 6,405
  • 21
  • 76
  • 127