Destructors

Destructors are special functions like constructors. They are called by the compiler when the life of an object is ending. Details of destructors are explained in this post.

Last Reviewed and Updated on February 7, 2020
Posted by Parveen(Hoven),
Aptitude Trainer and Software Developer

My C/C++ Videos on Youtube

Here is the complete playlist for video lectures and tutorials for the absolute beginners. The language has been kept simple so that anybody can easily understand them. I have avoided complex jargon in these videos.

Destructors are special functions, just like we have constructors. A constructor is called when the object is being created, and the destructor is called when the life of an object is about to end.

Syntax

The destructor function has the same name as the class, but it begins with a tilde(~) like as shown below. The tilde sign distinguishes a destructor from the default constructor.

class CMyClass
{
    int i;
 
public:
    CMyClass(int x) : i(x)
    {
        cout << "ctor called" << endl;
    }
 
    // destructor
    ~CMyClass()
    {
        cout << "dtor called" << endl;
    }
};

A destructor function doesn't return anything, not even void. This is similar to a constructor. The destructor cannot accept any arguments. So there's only one destructor in a class, the one that takes no arguments; but it's never called the default destructor.

What is a Destructor used for?

The very fact that the code inside a destructor is automatically called by the compiler, and that too at a particular point of the lifetime of an object is an exciting thing that ought to have a use.

We know that a constructor ensures that an object is initialized properly before use. But do we need a constructor at all? The answer is: No. But when I say no, then I will add another thing - you don't even need a class in the first place, C programs are written with global functions only. And, if someone were to go even further: even functions are not required, write your code in assembly language, and if the assembly language looks a bit heavy, then machine language is also there as an option! So why are people using classes, and then constructors, all of which are un-necessary? The whole point is to automate as many things through compiler based checks so that once you write your code properly, there is an implicit guarantee that it would work and deliver the desired results.

That's why destructors are there. They help prevent memory leaks. Just like constructors help us remember initialization, the destructors help in "cleanup", to release memory that needs to be released. A class can allocate memory on the heap with the new operator, or by using functions like malloc and calloc. The heap allocation has to be removed also; it's the responsibility of the same class. If the memory is not de-allocated, and your application exits, the operating system will still maintain a lock on that block of memory, preventing its allocation to some other needy application. This irresponsibility will eventually cause the PC to slow down, and people might stop using your applications.

Alternatives to a destructor could be functions with names like Dispose(). The users of the class will have to call them when they have finished using the class, i.e.., at the point of deletion of the class object. It is possible for users to forget calling such functions. Moreover, users might find it difficult to determine the last point of the class object. Global and static objects are deleted when the program exits. Objects created on the heap exit when the delete operator is used. A local stack object is deleted when the function or the enclosing scope blocks end. Hence, different types of objects die in different ways, and it could be difficult for a developer to keep track of all of them.

The following example shows a destructor in action. An int is allocated on the heap during construction, and the same int is released by the destructor. Run this code to see the messages that print.

class CMyClass
{
    int* mp_i;
 
public:
    // allocate an int on the heap
    // the value of the int is set 
    CMyClass(int x) : mp_i(new int(x))
    {
        cout << "memory allocated on heap" << endl;
    }
 
    // the dtor deletes the memory
    ~CMyClass()
    {
        delete mp_i;

        mp_i = 0;
 
        cout << "memory released" << endl;
    }
 
public:
    void show()
    {
        cout << *mp_i << endl;
    }
};
 

int main()
{
    CMyClass obj(9);
 
    obj.show();
 
    return 0;
}

Destructors can be called Explicitly

Whereas the constructors are solely called by the compiler and they cannot be explicitly called from outside[obj.CMyClass(); is wrong], except during the creation of an object, the destructors can be explicitly called[obj.~CMyClass(); is not wrong]. Consider the below code where we have added a call to the destructor. But this explicit calling will not prevent the compiler from running it's own call of the destructor.

class CMyClass
{
    int* mp_i;
 
public:
    // allocate an int on the heap
    // the value of the int is set 
    CMyClass(int x) : mp_i(new int(x))
    {
        cout << "memory allocated on heap" << endl;
    }
 
    // the dtor deletes the memory
    ~CMyClass()
    {
        delete mp_i;
 
        mp_i = 0;
 
        cout << "memory released" << endl;
    }
 
public:
    void show()
    {
        cout << *mp_i << endl;
    }
};
 

int main()
{
    CMyClass obj(9);
 
    obj.show();
 
    // calling the destructor manually/explicitly
    obj.~CMyClass();
 
    return 0;
}

If you run the above code, you will see two calls of the destructor. The second call will be the call from the compiler. So what happens if the compiler tries to release an already released memory? It should surely give rise to an error; and it does, if you do not set the pointers to zero or NULL. The delete operator applied to a zero, or NULL is a nop, no operation. That's why it is recommended to set a pointer to zero after the memory is released. If you remove the line mp_i = 0 from the destructor above, and run the code, you will end up with an error message.

But when do you need to call a destructor explicitly? The only time you will need to call a destructor explicitly is when you use the new operator to allocate memory at a given address, the address of your choice. This is usually required in embedded hardware systems. The normal "new" operator is not useful in such cases because it allocates memory at a location of its choice. C++ provides a "placement new" operator for such cases. The memory allocated with the placement new is not cleared by the normal delete operator. But C++ doesn't provide any "placement delete" operator. This means that if you create an object of a class through placement new, the destructor of that object doesn't automatically get called when "delete" is applied to that object. So, in such cases the developer has to explicitly call the destructor.

If you explicitly call a destructor of a class where you haven't written any destructor, then the compiler provided destructor is called, but that has no effect because compiler provided destructors or constructors do not have any code written inside them.

File Handling and Destructors

Destructors are also used to close open files, open network streams, database connections because these also allocate memory on the heap, and their cleanup code runs when their respective C functions(whatever) are called. If you are writing a class that uses the C functions, then you must make use of your destructor to de-allocate the memory. But if the file/database code is wrapped inside a class by someone else then it is highly probable that he has already taken care of cleanup through the destructor of that class. In that case you do not have to do any cleanup. In the following code a file is read and displayed on the console. Even though the destructor contains a cleanup code, strictly speaking it is not required because the class ifstream already has a destructor that is taking care of the cleanup. The destructor of the hosted object[ifs below] is run when the CMyClass object is about to be deleted.

#include <fstream>
#include <string>
#include <iostream>
 
using namespace std;
 
class CMyClass
{
    ifstream ifs;
 
public:
    // assuming that the file readme.txt is 
    // lying in the same folder as your
    // exe file
    CMyClass() : ifs("readme.txt")
    {
        
    }
 
    ~CMyClass()
    {
        // automatically close
        // cleanup is NOT required
        // because the destructor of ifs
        // is in any case going to do 
        // the cleanup
        if(ifs.is_open())
        {
            ifs.close();
        }
    }
 
public:
    void print()
    {
        if(ifs.is_open())
        {
            string strLine;
 
            // read each line
            while(getline(ifs, strLine))
            {
                // display to console
                cout << strLine << endl;
            }
        }
    }
};
 

int main()
{
    CMyClass obj;
 
    obj.print();
    
    return 0;
}

static Destructors

Just as static constructors are not possible in C++, destructors also cannot be marked static. It is easy to see why. A static destructor can have access only to the static members of that class. And, since there is only one destructor per class, how would you cleanup any non-static data members?

Destructors of Global or static Objects

Destructors of global and static objects are called after the main function returns, or as a result of calling the exit() function. The order of destructor call is reverse of the order in which these objects are installed in the global area of memory. As a sideline, you can note that all of your objects(global, local or whatever) are destroyed before cout so that you can use cout in the destructors of your objects. cout is destroyed last of all.. This assumes, of course, that you are running a console based application that includes the iostream header file.

In the following code, the class object is created in the global area of memory. Global objects are created before entering main, and they are deleted after the main ends. So we can verify that the code in the constructor runs before main, and the code in the destructor runs after main. Thus, we have an easy method of running any code before and after main.

class CMyClass
{
 
public:
    CMyClass()
    {
        cout << "ctor called" << endl;
    }
 
    ~CMyClass()
    {
        cout << "dtor called" << endl;
    }
};
 
// global
CMyClass obj;
 
int main()
{    
    cout << "entering main" << endl;
 
    // some other code
 
    cout << "exiting main" << endl;
 
    return 0;
}

Classroom Training

Classroom training in C/C++ is available at our training institute. Click here for details. You can also register yourself here.

Video Tutorial

We have created a video tutorial that can be downloaded and watched offline on your windows based computer. It is in the form of an exe file. No installation is required, it runs by double clicking the file. Since the exe file is hosted on the Google Drive, it should be very safe because Google itself checks for any virus or malware. The video can be watched offline, no internet is required.

Pricing

This single video will cost you USD $5. When you download the video, you will be able to watch the first few minutes for free, as a sample. The video app will prompt you for payment through PayPal and other payment options. If you want ALL VIDEOS, NOT JUST THIS ONE then go here: Complete Set of C/C++ Video Tutorials The entire set is priced at USD $50.

Screenshots

This is a screenshot of the software that should give you a good idea of the available functionality. Click on the image to see a larger view. screenshot of the video being played in the software

Installation

This software doesn't require any installation. Just download and double-click to run it. It doesn't require administrative priviliges to run. It runs in limited access mode, so should be very safe.

supports windows xp and later Supported Operating Systems

These videos can be run on 32-bit as well as 64-bit versions of the Microsoft Windows Operating Systems. Windows XP and all later OS are supported. If you want to run it on Windows XP and Windows Vista, then you must also have the .NET Framework Version 3.5 installed on your machines. Those users who have Windows 7 and later donot have to worry because these operating systems already have the .NET Framework installed on them.

Download Links

IMPORTANT NOTE: This download contains ONLY ONE video. The video is about the topic of this tutorial.

Want ALL Videos? If you want ALL VIDEOS, NOT JUST THIS ONE then go here: Complete Set of C/C++ Video Tutorials. TIP: If you plan to buy these videos, then it would be more economical to buy the entire set.

DISCLAIMER: Even though every care has been taken in making this software bug-free, but still please take a proper backup of your PC data before you use it. We shall not be responsible for any damages or consequential damages arising out of the use of this software. Please use it solely at your own risk.

Please download the software here.
download the video Destructors



Creative Commons License
This Blog Post/Article "Destructors" by Parveen (Hoven) is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.
Updated on 2020-02-07. Published on: 2015-11-19