7

From c++ FAQ: http://www.parashift.com/c++-faq-lite/dtors.html#faq-11.9

Remember: delete p does two things: it calls the destructor and it deallocates the memory.

If delete deallocates the memory, then what's the need of the destructor here?

Deduplicator
  • 44,692
  • 7
  • 66
  • 118
Aquarius_Girl
  • 21,790
  • 65
  • 230
  • 411
  • This is the garbage collection fallacy: memory is not the only resource that needs cleanup. – R. Martinho Fernandes Feb 03 '12 at 07:50
  • 1
    @R.MartinhoFernandes Explaining in detail would be helpful. One liners aren't usually easy to understand. – Aquarius_Girl Feb 03 '12 at 07:53
  • I'm saying that if delete only released the memory, it wouldn't cleanup other resources, like closing files, or network connections, or releasing locks. – R. Martinho Fernandes Feb 03 '12 at 07:55
  • @AnishaKaul And imagine the destructor of std::shared_ptr: it has to _conditionally_ delete the held pointer **and** decrease a refcount (possibly in thread safe fashion) – sehe Feb 03 '12 at 08:25
  • 6
    Before a man dies, he may want to sell his car, break up with his girlfriend and cancel his subscription to Wired Magazine. The recipe describing all of those necessary steps before death is called the "destructor". Note the *before* part. The destructor does *not* include the demise of the person itself, because no sane human being would state "Before death gets his eternal grip on my soul, I want to make sure I die first." – fredoverflow Feb 03 '12 at 09:42
  • @FredOverflow That's a nice one. But in a destructor, we need to do extra work "ourselves"? right? – Aquarius_Girl Feb 03 '12 at 09:48
  • 2
    Memory allocation and object construction are two separate and distinct concepts in C++. Deallocations pertains to the former, destruction to the latter. – Kerrek SB Feb 03 '12 at 09:49
  • If simple memberwise destruction does the right thing (if your members are `std::string` and `std::vector` and such), you don't need to write a destructor yourself. If it doesn't do the right thing (if your members are `char*` or `FILE*` or whatever), you must write a destructor doing the right thing. (Note that destructing a pointer [does nothing](http://stackoverflow.com/questions/4260464/).) So if you want to execute `delete member_pointer` before an object dies, you have to explicitly say so in the destructor. See [this related FAQ](http://stackoverflow.com/questions/4172722/) for details. – fredoverflow Feb 03 '12 at 09:57

9 Answers9

13

If delete deallocates the memory, then what's the need of the destructor here?

The point of the destructor is to execute any logic required to clean up after your object, for example:

  • calling delete on other objects owned by the object being destroyed
  • properly releasing other resources like database connections; file handles and the like
razlebe
  • 7,134
  • 6
  • 42
  • 57
  • Ah, so you mean that delete deletes a particular object and calls the destructor which deleted the children of the object deleted by delete? – Aquarius_Girl Feb 03 '12 at 07:52
  • 2
    @AnishaKaul: well ... not exactly: the actions are reversed. Delete first calls the destructor (that do what you code to do, like deleting something more, closing a file or whatsoever) THEN gives the object memory back to the system. – Emilio Garavaglia Feb 03 '12 at 08:01
  • @EmilioGaravaglia If I don't write any code in the destructor, it won't delete the children of the deleted object? – Aquarius_Girl Feb 03 '12 at 08:10
  • 1
    @AnishaKaul: yes it doesn't. The concept of "children of the object" is something known to you, not to C++. C++ just knows there are pointers to something else. Whether they have to be delete as well or left at their place (because used also by someone else) is something belonging to your logic, that is unknown to the compiler if you din't specify it. The way to specify it is the destructor code. If you want you can think to destructors as "event handlers" that are triggered upon delete. – Emilio Garavaglia Feb 03 '12 at 08:17
  • @EmilioGaravaglia Wow, so is the destructor of any use after delete? we anyway hhave to write the code ourselves, so we can write it whereever we want? – Aquarius_Girl Feb 03 '12 at 08:19
  • @Anisha: If your object manages heap-allocated objects (the ones created with `new`), and you want them to be deleted together with your object, you have to delete them in your destructor. See paxdiablos answer. – Stephan Feb 03 '12 at 08:20
10

You need to call the destructor in case there are other things that need to be done other than just de-allocating memory.

Other than very simple classes, there usually are.

Things like closing file handles or shutting down database connections, deleting other objects that are pointed to by members data within your object, and so forth.

A classic example is the implementation of a stack:

class myStack {
    private:
        int *stackData;
        int topOfStack;

    public:
        void myStack () {
            topOfStack = 0;
            stackData = new int[100];
        }

        void ~myStack () {
            delete [] stackData;
        }

        // Other stuff here like pop(), push() and so on.
}

Now think of what would happen if the destructor was not called every time one of your stacks got deleted. There is no automatic garbage collection in C++ in this case so the stackData memory would leak and you'd eventually run out.


This requiring of a destructor to delete all its resources moves down the tree towards the basic types. For example, you may have a database connection pool with an array of database connections. The destructor for that would delete each individual database connection.

A single database connection may allocate a lot of stuff, such as data buffers, caches, compiled SQL queries and so on. So a destructor for the database connection would also have to delete all those things.

In other words, you have something like:

+-------------------------------------+
| DB connection pool                  |
|                                     |
| +-------------------------+---+---+ |
| | Array of DB connections |   |   | |
| +-------------------------+---+---+ |
|                             |   |   |
+-----------------------------|---|---+
                              |   |   +---------+
                              |   +-> | DB Conn |
             +---------+      |       +---------+
             | DB Conn | <----+         /  |  \
             +---------+         buffers   |   queries
               /  |  \                  caches
        buffers   |   queries
               caches

Freeing the memory for the DB connection pool would not affect the existence of the individual DB connection or the other objects pointed to by them.

That's why I mentioned that only simple classes can get away without a destructor, and those are the classes that tend to show up at the bottom of that tree above.

A class like:

class intWrapper {
    private:
        int value;
    public:
        intWrapper () { value = 0; }
        ~intWrapper() {}
        void setValue (int newval) { value = newval; }
        int getValue (void) { return value; }
}

has no real need for a destructor since the memory deallocation is all you need to do.


The bottom line is that new and delete are opposite ends of the same pole. Calling new first allocates the memory then calls the relevant constructor code to get your object in a workable state.

Then, when you're done, delete calls the destructor to "tear down" your object the reclaims the memory allocated for that object.

paxdiablo
  • 854,327
  • 234
  • 1,573
  • 1,953
  • `so the stackData memory would leak and you'd eventually run out.` Didn't understand this. Delete deallocates the memory, so calling delete on a stack would deallocate it, so how are the memory leaks happening? – Aquarius_Girl Feb 03 '12 at 07:57
  • @Anisha, a destructor is totally responsible for cleaning up after itself. That means it must also delete any dynamically created objects that it has created during its lifetime (usually, but not necessarily always, in its constructor). The acto of deleting its resources may further move down the tree. See my updated answer. Freeing the memory for a myStack object does _not_ free any memory it has allocated, its destructor is responsible for that. – paxdiablo Feb 03 '12 at 07:58
  • So, destructor cleans up the allocated children of the destroyed objects? – Aquarius_Girl Feb 03 '12 at 08:09
  • @Anisha, yes, although there are _other_ things (than simply calling `delete`) that it may need to do as part of that cleanup (like closing down legacy C libraries that don't use objects). – paxdiablo Feb 03 '12 at 08:15
  • `has no real need for a destructor since the memory deallocation is all you need to do.` In that class, you didn't allocate any memory, so we don't we to deallocate anything. The destructor will still be needed for destroying the object `intWrapper a;`? Right? – Aquarius_Girl Feb 04 '12 at 06:55
  • 1
    No, you don't need a destructor, C++ will simply deallocate the memory - it implicitly supplies a destructor that does nothing if you don't provide your own. You need to understand that memory allocation/deallocation and construction/destruction are two different things, just that new and delete use them both. For example, `delete [] arr` will call the destructor once per object in the array ut may only deallocate one block of memory. – paxdiablo Feb 04 '12 at 08:38
  • `You need to understand that memory allocation/deallocation and construction/destruction are two different things,` Well, I truly do NOT understand how they are different things. Ah! Do you mean the construction refers to the manual `new` and allocation refers to the objects like `classX objX;`? – Aquarius_Girl Feb 04 '12 at 08:43
  • 1
    @Anisha, read the final two paragraphs in my answer carefully: `new` does _two_ things. The first is to allocate the memory (like C's `malloc`) for your object, the second is to call your constructor so you can set the object up. At the other end `delete` also does _two_ things. It calls the destructor so you can tear down your object and then it reclaims the memory (a la C's `free`). I'm not sure I can explain it any clearer and the comments are filling up so, if it's still not clear, you may want to consider asking a new question just on that aspect. – paxdiablo Feb 04 '12 at 10:31
3

Suppose you have a class that dynamically allocates memory:

class something {
public:
    something() {
        p = new int;
    }

    ~something() {
        delete p;
    }

    int *p;
};

Now let's dynamically allocate a something object:

something *s = new something();

delete s;

Now, if the delete didn't call the destructor, then s->p would never be freed. So delete has to both call the destructor and then deallocate the memory.

flight
  • 7,162
  • 4
  • 24
  • 31
  • Ah, that's nice. So, Ah, so you mean that delete deletes a particular object and calls the destructor which deleted the children of the object deleted by delete? – Aquarius_Girl Feb 03 '12 at 07:59
  • Does this also mean that after deleting the parent object explicitly there are no chances of memory leaks due to paren't children? – Aquarius_Girl Feb 03 '12 at 08:02
  • For the first question, it calls the destructor *first* and then deletes the object. Because obviously, if you delete the object first, then how can you destruct it? – flight Feb 03 '12 at 10:18
  • For the second: Not necessarily. Deleting the parent object only guarantees that the destructor will be called. If you messed up your constructor then it won't delete correctly but assuming you did make your destructor correctly, then yes, there are no chances of memory leaks. – flight Feb 03 '12 at 10:20
2

The destructor is in charge of freeing resources other than the object's allocated memory. For instance, if the object has a file handle open, the destructor could call fclose on it.

StilesCrisis
  • 15,972
  • 4
  • 39
  • 62
1

It deallocates the memory taken up by that object. However, anything that has been allocated by the object (and owned by that object) needs to be taken care of in the destructor.

Also, in general ... FAQs ... usually not wrong.

Brian Roach
  • 76,169
  • 12
  • 136
  • 161
0

if you declare a class normal (not pointer), it automatically calls constructor and call destructor automatically when the program closes. If you declare as pointer, it call the constructor when initializes using new and does not call destructor automatically until you call delete that pointer using delete

Riskhan
  • 4,434
  • 12
  • 50
  • 76
0

The destructor is there to clean up the changes that the object constructor and member functions might have done to the program state. That can be anything - remove the object from some global list, close an opened file, free allocated memory, close a database connection, etc.

sharptooth
  • 167,383
  • 100
  • 513
  • 979
0

The destructor would not have been a mandatory feature. The languages like, C, Java, C# don't have destructors. C++ also can live without it.

Destructor is a special facility provided by C++ (same as Constructor). It's called when an object is "destroyed".

Destroy means, the object scope is officially finished and any reference to that object will be illegal. For example:

A* foo ()
{
  static A obj;  // 'A' is some class
  A *p = &obj;
  return p;
}

In above code, obj is a static data created of type A; foo() returns a reference to that obj which is ok, because obj.~A() is not yet called. Suppose obj is non-static. The code will compile, however, A* returned by foo() is now pointing to a memory location which is no more an A object. Means -> the operation is bad/illegal.

Now, you should be able to distinguish between deallocation of the memory and the destruction of the object. Both are tightly coupled, but there is a thin line.

Also remember that destructor can be called at multiple places:

int bar ()
{
  A obj;
  ...
  return 0; // obj.~A() called here
  ...
  return 1; // obj.~A() called here
  ...
  return 2; // obj.~A() called here
}

In above example, obj.~A() will be called only once, but it can be called from any of the places shown.

During the destruction, you may want to do some useful stuff. Suppose class A calculates some result, when the object destroys; it should print the result of calculation. It can be done in C style way (putting some function at every return statement). But ~A() is a readily available one-stop facility.

iammilind
  • 68,093
  • 33
  • 169
  • 336
  • `but it can be called from any of the places shown` How's that possible? When the `return 0` is met, the funtion returns, and the remaining code can NEVER get executed, isn't it? – Aquarius_Girl Feb 03 '12 at 08:17
  • @AnishaKaul, yes that's the point. `obj.~A()` is called **only once**, but compiler emits it code at all the above places shown. Because compiler doesn't know that at runtime which `return` will be executed. – iammilind Feb 03 '12 at 08:20
0

In addition to answers focused on the objects allocated on the heap (with new; which are deallocated only with delete)...Don't forget that if you place the object on the stack (so, without using new), its destructor will be called automatically and it will be removed from the stack (without calling delete) when it goes out of scope. So you have one function that is guaranteed to be executed when object goes out of the scope and that is perfect place to perform cleanup of all other resources allocated by the object (various handles, sockets...and objects created on the heap by this object - if they must not outlive this one). This is used in the RAII idiom.

Bojan Komazec
  • 9,216
  • 2
  • 41
  • 51