Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

As the delete operator deallocates memory, why do I need a destructor?

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?

like image 298
Aquarius_Girl Avatar asked Feb 03 '12 07:02

Aquarius_Girl


2 Answers

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
like image 137
razlebe Avatar answered Oct 05 '22 06:10

razlebe


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.

like image 32
paxdiablo Avatar answered Oct 05 '22 07:10

paxdiablo