8.7 — Destructors

A destructor is another special kind of class member function that is executed when an object of that class is destroyed. Whereas constructors are designed to initialize a class, destructors are designed to help clean up.

When an object goes out of scope normally, or a dynamically allocated object is explicitly deleted using the delete keyword, the class destructor is automatically called (if it exists) to do any necessary clean up before the object is removed from memory. For simple classes (those that just initialize the values of normal member variables), a destructor is not needed because C++ will automatically clean up the memory for you.

However, if your class object is holding any resources (e.g. dynamic memory, or a file or database handle), or if you need to do any kind of maintenance before the object is destroyed, the destructor is the perfect place to do so, as it is typically the last thing to happen before the object is destroyed.

Destructor naming

Like constructors, destructors have specific naming rules:
1) The destructor must have the same name as the class, preceded by a tilde (~).
2) The destructor can not take arguments.
3) The destructor has no return type.

Note that rule 2 implies that only one destructor may exist per class, as there is no way to overload destructors since they can not be differentiated from each other based on arguments.

Generally you should not call a destructor explicitly (as it will be called automatically when the object is destroyed), since there are rarely cases where you’d want to clean up an object more than once. However, destructors may safely call other member functions since the object isn’t destroyed until after the destructor executes.

A destructor example

Let’s take a look at a simple class that uses a destructor:


If you compile the above example and get the following error:

error: 'class IntArray' has pointer data members [-Werror=effc++]|
error:   but does not override 'IntArray(const IntArray&)' [-Werror=effc++]|
error:   or 'operator=(const IntArray&)' [-Werror=effc++]|

Then you can either remove the “-Weffc++” flag from your compile settings for this example, or you can add the following two lines to the class:

We’ll discuss what these do in chapter 9.

This program produces the result:

The value of element 5 is: 6

On the first line, we instantiate a new IntArray class object called ar, and pass in a length of 10. This calls the constructor, which dynamically allocates memory for the array member. We must use dynamic allocation here because we do not know at compile time what the length of the array is (the caller decides that).

At the end of main(), ar goes out of scope. This causes the ~IntArray() destructor to be called, which deletes the array that we allocated in the constructor!

Constructor and destructor timing

As mentioned previously, the constructor is called when an object is created, and the destructor is called when an object is destroyed. In the following example, we use cout statements inside the constructor and destructor to show this:

This program produces the following result:

Constructing Simple 1
Constructing Simple 2
Destructing Simple 2
Destructing Simple 1

Note that “Simple 1” is destroyed after “Simple 2” because we deleted pSimple before the end of the function, whereas simple was not destroyed until the end of main().

Global variables are constructed before main() and destroyed after main().


RAII (Resource Acquisition Is Initialization) is a programming technique whereby resource use is tied to the lifetime of objects with automatic duration (e.g. non-dynamically allocated objects). In C++, RAII is implemented via classes with constructors and destructors. A resource (such as memory, a file or database handle, etc…) is typically acquired in the object’s constructor (though it can be acquired after the object is created if that makes sense). That resource can then be used while the object is alive. The resource is released in the destructor, when the object is destroyed. The primary advantage of RAII is that it helps prevent resource leaks (e.g. memory not being deallocated) as all resource-holding objects are cleaned up automatically.

Under the RAII paradigm, objects holding resources should not be dynamically allocated. This is because destructors are only called when an object is destroyed. For objects allocated on the stack, this happens automatically when the object goes out of scope, so there’s no need to worry about a resource eventually getting cleaned up. However, for dynamically allocated objects, the user is responsible for deletion -- if the user forgets to do that, then the destructor will not be called, and the memory for both the class object and the resource being managed will be leaked!

The IntArray class at the top of this lesson is an example of a class that implements RAII -- allocation in the constructor, deallocation in the destructor. std::string and std::vector are examples of classes in the standard library that follow RAII -- dynamic memory is acquired on initialization, and cleaned up automatically on destruction.

Rule: If your class dynamically allocates memory, use the RAII paradigm, and don’t allocate objects of your class dynamically

A warning about the exit() function

Note that if you use the exit() function, your program will terminate and no destructors will be called. Be wary if you’re relying on your destructors to do necessary cleanup work (e.g. write something to a log file or database before exiting).


As you can see, when constructors and destructors are used together, your classes can initialize and clean up after themselves without the programmer having to do any special work! This reduces the probability of making an error, and makes classes easier to use.

8.8 -- The hidden “this” pointer
8.6 -- Overlapping and delegating constructors

145 comments to 8.7 — Destructors

  • somoe

    Is it necessary to do this?
        if (m_array)
            delete[] m_array;

  • Anthony

    Many thanks for the reply! Uniform initialization aside, this leads me to ask more question:

    class IntArray {
        int *m_array;  // "
        IntArray(int length) : m_length(length), m_array(new int[(length > 0)? m_length : 0]) {  // <-- IS THIS SAFE?
        IntArray(int length) : m_length(length), m_array(new int[(length > 0)? length : 0]) {  // <-- OR RESORT TO THIS?

    The first option keeps @m_length with @m_array, as you recommended in your answer to my previous question. But now that I'm using an initializer list, is @m_length guaranteed to have been initialized by the time I use it to initialize the array?

    • Yes. Members are initialized in the order of their declaration. Since @m_length is declared in line 3 and @m_array in line 4, @m_length is guaranteed to be initialized before @m_array.
      If they were swapped, you should either use @length when allocating @m_array, or allocate @m_array in the constructor's body.

  • Anthony

    I have a very trivial question, but it's one I've often wondered about. It's when you initialize a variable using the value of another, and then you have a choice about how you initialize the next variable. Should you use the original variable, or the one you just initialized? Like this:

    class IntArray {
        int m_length;
        int *m_array;
        IntArray(int length) {
            m_length = length;
            m_array = new int[length];  // <-- THIS?
            m_array = new int[m_length];  // <-- OR THIS?

    What is best practice?

    Thank you for a great tutorial. I am new to C++ and do a little bit every day.

    • Hi Anthony!

      @m_length is directly connected to @m_array. It will always describe the number of elements in @m_array.
      @length might be different, maybe you want to store 1 extra element or you get the length from somewhere else.
      So use @m_length.
      You should initialize the variables in the constructor initializer list.

  • Mike

    When I compile the code below I get the error: "error: 'IntArray::m_array' should be initialized in the member initialization list [-Werror=effc++]|".

    However, I can overcome the error by making an initializer list like this

    but this way, I will not be able to assert the length of the dynamic array, so what should I do? should I just keep the assert inside the body of the constructor?

    • Hi Mike!

      * Line 7, 8: Initialize your variables with brace initializers.

      C++20 will add contracts that allow you to sanitize arguments before the function body is entered.
      Simply moving the initialization into the member initializer list isn't good, because the allocation is attempted before the assert is run, possibly crashing your program.
      You can add a conditional operator into the initialization of @m_array to make sure you're not getting undefined behavior.

      Note that @m_array is initialized with size 0 if @length is invalid. Dynamically allocated arrays are allowed to have no elements.

  • Ruben

    I have a question about re-assigning variables. Is an instance destroyed when a variable holding a class is re-assigned?

    I tried to check this using below example:

    However this gives me the following output:

    Created instance with ID = 1
    I am instance with ID = 1

    Going to re-assign test with a new instance with id=2
    Created instance with ID = 2
    Instance with ID 2 destructed     <====== HERE I WOULD EXPECT INSTANCE WITH ID=1 TO BE DESTRUCTED
    test has been reassigned
    I am instance with ID = 2
    Instance with ID 2 destructed

    It seems that the destructor is called indeed when the variable is re-assigned but it displays the wrong ID.... ???

    • Hi Ruben!

      * Line 7: Initialize your variables with brace initializers. You used copy initialization.
      * Line 31, 35: Initialize your variables with brace initializers. You used direct initialization.

      The output is correct. In line 35, @MyClass with id 2 gets constructed and it's contents are immediately copied to @test using @MyClass::operator= (covered later). The temporary @MyClass object is no loger used, so it gets destructed.
      @test is destructed when its lifetime ends. Re-assignment doesn't kill instances.

      Think of it like this

      Line 4 doesn't destruct @ferrari. There are still 2 separate variables. Modifying either other doesn't affect the other.

  • Clapfish

    Hi guys!

    I get the following errors when I try to compile the code in the 'A destructor example' section:

    |4|error: 'class IntArray' has pointer data members [-Werror=effc++]|
    |4|error:   but does not override 'IntArray(const IntArray&)' [-Werror=effc++]|
    |4|error:   or 'operator=(const IntArray&)' [-Werror=effc++]|

    Could someone explain what's going on here and how I might fix it?


    • Hi Clapfish!

      @IntArray has a pointer member variable (@m_array). The default copy constructor or assignment operator would copy the pointer to the new object, but not the object that the pointer is pointing to. Since @m_array is dynamically allocated and automatically deleted by the class, this would result in a double delete.
      To fix this, you have to write a copy constructor and assignment operator. Since you can't to this now, and pointer members aren't always automatically handled, I suggest you to change -Werror=effc++ to -Weffc++ in your compiler settings. Doing so will change the error to a warning.
      g++ (I guess you're using g++) seems to be pretty strict about effc++, even if there are situations in which you're doing nothing wrong.

  • Marcos O.

    If the class destructor is called manually why does it not destruct the object? Is there code that is implicitly called when using @delete on a dynamically allocated object that differs from the defined destructor?

    The first simple created is still destructed as leaving @main() instead of when destructor called.

    • > If the class destructor is called manually why does it not destruct the object?
      The object's memory is freed when delete or @std::free is used on a pointer to it. Before freeing memory, the destructor is called to allow manual deconstruction of the object.
      The destructor is not responsible for low-level freeing of the object it belongs to. This is handled by your compiler/OS.
      Non-pointer objects cannot be deleted manually.

      • Marcos O.

        Ok thanks, so the destructor if fully written would initialize a pointer to the object and then free it? Would you set the pointer to a null value or delete it? Would that also automatically free the memory associated to the member objects within or do you have point to them individually?

        • > pointer
          Which pointer?

          The destructor shouldn't initialize anything. It should be used to free memory of members that were dynamically allocated.
          If you delete something, it can be helpful to prevent a double delete, though, this might cause some bugs to go unnoticed.
          Nothing that is dynamically allocated is freed automatically. Everything that is not dynamically allocated is freed automatically.

  • 7.1 Practice Task 1                            [Expected time = 15mins]
    Partial solution of a List Class is given below.  Complete the missing code in the functions to run the program properly.

    int *elements;
    int size;
    int length;
    ////////////////////////////////// Constructor
    List(int maxsize)
        elements=new int[size];
    /////////////////////////////////// Destructor
    ~List ()
        delete []elements;
    ///////////////////////////////////  Output the list structure
    void showStructure ()
            for(int i=0;i<length;i++)
                cout<<"Display: No items to be displayed. List is empty\n";
    ////////////////////////////////// List manipulation operations
    // Insert after cursor
    void insert (int newDataItem)  
            cout<<"Insert: Cannot insert more items. List is full\n";
    // Remove data item
    int remove ()      
            return elements[length];
            cout<<"Remove: Cannot remove the item. List is empty\n";
    // Replace data item
    void replace ( int newDataItem, int position )
        //Condition: List contains at least position+1 data items.
        //Result: Removes the data item present at the position from a list and replace the number requested by user at its position.
            cout<<"Replace: Cannot replace the item. Invalid position requested\n";
            //implement your logic here
    // find any number
    bool find ( int searchDataItem )
        //Condition: List is not empty.
        //Result: Check if the number is present in the list or not
            for(int i=0;i<length;i++)
                //implement your logic here


    /////////////////////////////////////// List status operations

    // check if List is empty
    bool isEmpty ()  
        // implement your logic here

    // check if List is full                    
    bool isFull ()                        
        // implement your logic here

    7.2 Practice Task 2                            [Expected time = 20mins]
    Implement List class with the following functions:
    1)    Sequential insert in the list
    2)    Sequential delete in the list
    3)    Insert a value at a specific index and adjust remaining list afterwards
    4)    Delete a value at a specific index and adjust remaining list afterwards
    5)    Show all values present in the list
    6)    Show the length of the list
    7.3Practice Task 3                            [Expected time = 20mins]

    Create a list of atleast 10 students. Program should save the following information for each student: Name, Reg. No., CGPA and Semester. Now perform the following tasks:
    a)    Display only those students whose CGPA is greater than 3.0
    b)    Display the students of 3rd and 4th semester
    c)    Display the students alphabetically

    7.4Out comes

    After completing this lab, student will be able to understand the concepts related to dynamic list using arrays and stack abstract data type. They will be able to develop programs related to dynamic lists using arrays in C++ using Microsoft Visual Studio 2008 environmen

  • Udit

    As much as I understand, if you do not wont go for dynamic allocation using new and use normal initialization, then program would call destructor by itself

    Inside constructor
    Inside destructor

    However, when we allocate using dynamic allocation using new, then program wont call destructor by itself and you have to delete the pointer then desctructor would be called.

    Inside constructor

    Please mention if my understanding is correct

  • Aditya

    Can you please elaborate more on RAII with example.

  • Ishak

    Does pSimple disobey the RAII technique, because it seems we are dynamically allocating object simple 2?

    Thank you for the help and the outstanding material;

  • Peter Baum

    I thought the name "Resource Allocation Is Initialization" was a strange turn of phrase.  I found this explanation and detailed description of its origin extremely helpful:

  • Peter Baum

    Section Destructor Naming
    "Just like constructors, destructors should not be called explicitly."

    I got hung up on this sentence.  We just saw in the previous lesson how a constructor can call another constructor (explicitly).  Also, I didn't understand why I couldn't call a destructor explicitly.  I would think it is just another function that the system calls prior to destroying an object, but if I call it, it just returns to me, so "no harm, no foul."

    It may be that this issue is made clear later in the lesson, but eliminating confusion along the way might be a consideration.

    • Peter Baum

      Here is a program that shows that you can explicitly call the destructor.  The only thing that is a little strange is that it appears that the destructor is not called automatically to delete the object when main() ends.  You can see this behavior if you comment out the delete.  The destructor IS called (a second time) if the object is explicitly deleted.

      • Alex

        In visual studio, the object gets destructed twice in your example regardless of whether you do dynamic or non-dynamic allocation. If that's not happening with your compiler, it may be a compiler bug.

    • Alex

      I think that line was written before C++11 added constructor chaining. I've updated the text to the following: "Generally you should not call a destructor explicitly (as it will be called automatically when the object is destroyed), since there are rarely cases where you'd want to clean up an object more than once".

      You _can_ call a destructor explicitly, but you generally _shouldn't_.

  • Are constructors and destructor belong to "member function"?

  • Matt

    "Rule: If your class dynamically allocates memory, use the RAII paradigm, and don’t allocate objects of your class dynamically."

    I wanted to make sure I understood this rule, so my original question was as follows:

    Suppose I have a class (A) that dynamically allocates memory, and for some reason I need to dynamically allocate objects of that class (violating RAII), would the proper way to handle that situation be to create another class (B) that has the first class as a member?  That way I could statically allocate B, which would dynamically allocate A, which would dynamically allocate A's member variables.  As such, B could handle cleanup and we maintain RAII.

    So in order to write that question, and hopefully be able to show an example of what I was talking about, I attempted to write the following code that piggy-backs off of your original example.  I failed to do so in a couple places, hopefully my comments illustrate what problems it has (and allow you to answer my original question); however, perhaps more importantly now that I've failed so severely to write this, you could tell me how to accomplish what I was trying to do here in the first place!:

    • nascardriver

      Hi Matt!

      I disagree with this rule.
      'A' is a class that dynamically allocates memory.
      Creating @A dynamically is only problematic if you're never deleting @A which is the worse problem of the two.
      So, if you're doing something bad, the outcome gets worse, but it's bad anyway. This is like dying in a car crash vs dying in a hospital.
      (car crash = crashing, because leaking, because no delete and therefore no resource free)
      (hospital = slowly crashing, because no delete but resource free)

      I didn't look at your code, but your idea doesn't work, because class B would still create A dynamically, so you're just moving the "problem" rather than solving it.

      • Matt

        But B would have a destructor that ensures A gets deleted is my point, or does that not work?

        • nascardriver

          Ok, I get it now, it does work.
          Your B is a self made smart pointer (Chapter 15)

          • Alex

            Yup. If A allocates memory, and you need to dynamically allocate an object of type A, you should use a smart pointer (such as std::unique_ptr) to manage your object of type A. This will guarantee it gets cleaned up properly, while preserving RAII principles.

  • Frieder

    your statement about destructors not being called when using the exit-function might be problematical in some cases when the destructor just NEEDS to be called. What about the following possibility?

    cutTies had to be made static, but under most conditions (i.e. database connections to be cleaned up, ...) that would be ok, I think.

    Your opinion?


  • First

    what's the use of assert in program

  • Ajay

    How many times destructor gets call ?

  • The Perplexed Programmer

    Hello Alex!
    In your code, 'A destructor example', shouldn't line 7 and line 8 have the same indentation?

  • Connor

    Hi Alex,
    Can a class have a member function that calls its own destructor?

    I.E., can an obect call the destructor well before it goes out of scope, in order to destroy that object?

    • Alex

      You can... but you generally shouldn't. That functionality only exists for destructing objects created using placement new, which is an advanced technique.

      • Connor

        The reason I ask is I'd like to allow a user to destroy an object they've crated but I'm unsure of the syntax.

        doesn't work for me? Is there another way I should be implementing the destructor or changing the syntax?

        • Alex

          Users should kill objects in one of two ways:
          1) If they are statically allocated, by having them go out of scope.
          2) If they are dynamically allocated, by using the delete keyword.

  • Zoran

    In example program Simple, you use -> operator. I think that in this lesson, this confuses the reader.
    So I think that it would be better if the line

    is changed to

  • Curiosity

    This Prints :-
    Constructing Simple 1
    Destructing Simple 1
    Constructing Simple 2
    Destructing Simple 2
    Destructing Simple 2
    Destructing Simple 1

    Can u tell me Why? And Also, Tell Me How to fix it?
    Is it because an anonymous object is created on Line 31 due to which "destructing" is getting printed unexpectedly ?

    • Alex

      This is perfect kind of question to answer by stepping through your program line by line in the debugger and watching what it outputs.

      • Curiosity

        I did that too and that's how i thought that on Line 33 an anonymous object is created due to which it prints "Destructing" unexpectedly and I also think that "constructing" is also getting printed for anonmyous objects only ! Tell me If I'm Right ! But, i'm unable to create a fix for this. Please Give Me A Fix :)

        • Curiosity


          Is It The Right Fix ?
          Prints What I intended tho :)

          • Alex

            Close. Anonymous objects work just like normal objects, except they only live for an expression, then they get destroyed.

            However, swapping out your user-defined constructor for a compiler-generated one isn't good.

  • jenifer

    What is the reason for the destructor being called in the reverse order of constructors? The example you explained had dynamic objects,  but consider the case when an object goes out of scope normally.

    • Alex

      In most cases, variables are allocated on the stack. Things on the stack follow a first on last off policy, so the first object to get created is the last to get destroyed. It's analogous to a pile of plates where the first plate on the pile gets buried under all the others and is the last plate removed.

  • jenifer

    In the destructor example, Why are using return by reference here, when return by value works fine

    • Alex

      Get by value works fine if we expect this function to be read-only. By making it return a reference, we can use this as a getter or a setter. Given that, it might have been better to name this function value(), not implying it's just a getter.

      • pluq

        But then you would be modifying a private variable, no???? Isn't it for what private variable exist, to avoid be modified outside the class?

        • Alex

          Yes, this does violate abstraction. Since our return value is a fundamental type, we really should be returning by value here. I've updated the example accordingly.

  • AlexR


    To make sure I fully understand RAII, I modified half of your example code to do what I think you explained in that paragraph. I created the pointer and then assigned the dynamic memory in the Member Initialization List. After that I then assigned the value of the variable input to the dereferenced pointer. Then for my Destructor, I had it delete the dynamic memory.

    Is this what you were talking about? If not, it would be really amazing if you could put an example in there. Once again, I appreciate all the work you've put into this tutorial! It's very helpful.

  • What is the assert function used in the first example?

Leave a Comment

Put all code inside code tags: [code]your code here[/code]