Search

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 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.

Just like constructors, destructors should not be called explicitly. 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:

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
1
Constructing Simple 2
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

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).

Summary

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
Index
8.6 -- Overlapping and delegating constructors

97 comments to 8.7 — Destructors

  • 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

          Alex?

          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

    Hello!

    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 C++ code inside [code][/code] tags to use the syntax highlighter