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 constructors and destructors. A resource (such as memory, a file or database handle, etc…) is acquired in the object’s constructor. 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, as forgetting to deallocate those objects will result in a resource leak.

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.

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

58 comments to 8.7 — Destructors

  • sandor

    Hello,
    can I call the destructor explicitly?

    • Sandor, technically you can… but generally you shouldn’t.

      If the object is dynamically allocated, just delete it using the delete keyword, which will call the destructor anyway.

      If the object is not dynamically allocated, calling the destructor explicitly is actually dangerous. Consider what would happen if you explicitly call the destructor of a local variable -- the destructor would delete the variable. Then when the local variable went out of scope, the destructor would get called AGAIN. Then bad things happen.

      • sandor

        Ok, but how can I call it?.I thought of having for example several spaceship objects in the main function. Now for some reason one of those spaceships gets “shot down”, so I want to call the destructor to “destroy” it, but I don’t want to wait till the main function ends.

        • Sandor, if you need objects that may be destroyed in the middle of a function, the best way to go is to dynamically allocate them in the first place and then delete them using the delete keyword. You should not need to explicitly call the destructor.

          In the case where you have multiple objects (eg. spaceships), usually the best way to go is an array of pointers. If you need a new spaceship, find the first empty array slot and allocate a new spaceship there. If a spaceship is destroyed, delete it and then set the pointer in the array to NULL. This way, you can have as many spaceships as there are elements in the array. This also gives you the ability to loop through the array to do things to all the spaceships (eg. move them).

    • Use dynamic memory allocation to control the life time of the object.
      You can create anywhere and destroy it anywhere. When you delete an object, its destructor function will be executed

  • colton

    Alex, I want to tell you how much I appreciate all of the time you have spent on this tutorial. I have used some of the other online tutorials, (cplusplus.com, cprogramming.com, etc) but I find myself most always coming back here whenever I dont understand something and need a really thorough, cogent, and easy to understand explanation.

    Thanks!

  • Daniel

    If I have a class named “thing” and I create a static instance of that class named “myThing” like this “static thing myThing”. Is the destructor called on this instance? If so when? I would assume it would at the end of the programme but I really don’t know.

    • Daniel

      Well I just did a test myself and found that it was as I expected called at the end of the programme if anyone else wants to try this them selves this is what I did
      #include <iostream>
      using namespace std;

      class basic
      {
      public:
      basic() {
      cout << "constructor called" << endl;
      }

      ~basic() {
      cout << "destructor called" << endl;
      }
      };

      static basic myThing;

      int main()
      {

      system("pause");
      return 0;
      }
      It outputs:
      constructor called
      pause stuff
      destructor called

      • I find a lot of time when I have questions in C++ I can answer them just by writing a test program like you did.

        The answer is that when you have static variables, they get constructed before main() and destructed just before your program ends (assuming you don’t exit() early)

        • Daniel

          Thanks,

          QUOTE: assuming you don’t exit() early
          ah, is there an easy way around this? to call the destructor on an exit() call?

          • As far as I know, there’s no way to explicitly call the destructor on an exit() call.

            However, instead of using exit() to terminate your program, there are other options. One way is to design your program so it “exits normally” (eg. at the end of main) instead of wherever it happens to be at the moment. A related idea is to throw an exception and catch it in main(), allowing the program to exit normally.

  • Joe

    Shouldn’t the line where memory for an array of Simple objects is being dynamically allocated read:

    Simple *pSimple = new Simple[2] (using brackets instead of parenthesis)

    And isn’t it redundant to specify the object type at the beginning of the allocation? Couldn’t the line read pSimple = new Simple[2] ?

    I thought that when dynamic memory is being allocated it was understood that the identifier before the = operator is a pointer of the type specified after the word new.

    • If I was trying to allocate an array of Simple, then you would be correct. I was just trying to allocate a single one, passing the constructor the value 2.

      It IS redundant to specify the object type when doing an allocation -- however, C++ makes you do it anyway. In the next version of C++, you will be able to use the auto keyword to automatically infer the data type from the assignment.

  • jeremy

    hi alex,

    just want to ask.destructor cannot be overloaded right? but it can be called more than 1 time.
    as soon as each object is destroyed.
    in this code: } // cSimple goes out of scope here

    Was the destructor called twice?

    Please explain. thanks

    • Destructors can not be overloaded. They never take any parameters and never return anything.

      Destructors should not be called more than 1 time, which will happen automatically when the variable goes out of scope, or manually when you delete it. If you try to destruct a variable that has already been destructed, your program will crash.

  • KH

    i want to ask that for MyString(const char *pchString=””)
    why “” are needed? what is the uses?

    • baldo

      The “” simbolyze an empty string. So, the function parameter has a default value of an empty string. For example, you can put “default string” and if the user didn’t input any string when he called the MyString function, the parameter will have the default value of “default string”.

  • In your last example on this lesson, you included the characters “->”. Is this equivalent to the selector operator “.”?

    • baldo

      The characters “->” are used for member selection from pointers. The following two lines are equivalent:

  • SWEngineer

    Simple well explained tutorial.

    Thanks.

  • kriain1982

    If we instantiate a class by using new operator, we should call destructor explicitly. It won’t be called automatically for the objects which are created on the heap.

    • Alex

      No. If you instantiate a class via new, you should destroy it via delete, not by calling the destructor. Destroying the object via delete will implicitly call the destructor.

  • puppi

    hi alex,

    what are differenties between  "Allocate a Simple dynamically" and "Allocate a Simple on the stack" as you mentioned at the bottom of this tutorials? i don’t understand :/

  • cpplx

    in the lesson only main() is used to call the class and talking about destructors, i assume that it is called at the end of the block of any calling function. is that right? and what if the class call was made from other blocks nested in the function?

    • Alex

      A classes destructor is called when the class variable goes out of scope. For local variables, that’s typically at the end of the block in which they’re declared (which could be a nested block), but for other kinds of variables, it could also be elsewhere. For example, global variables get destructed when the program ends. Dynamically allocated variables get destructed when the program deletes them.

  • Connor

    Hello again Alex.
    I’m confused about passing "Alex" as a c-style string. I was under the impression that c-style strings had to be declared as an array as per lesson 6.6- C-Style Strings.
    When your name is passed to MyString(const char *pchString) wouldn’t *pchString be expecting a single char value vice a string? Shouldn’t it be:

    Thanks.

  • Joe

    I’m lost on this line:

    public:
        MyString(const char *pchString="")

    So the constructor takes a const char* called pchString, but what is =" "??? Inst that a pointer? Is that a default value of one space? And how can you assign a value to it? Its a pointer?

  • What would happen if I put the two functions (GetString() & GetLength()) before the destructor inside the class (In the first example)?

    • Alex

      You mean just reorder the function so GetString() and GetLength() appear before the destructor? Nothing, the order of functions and member variables in a class doesn’t matter.

  • Quang

    Sorry I’m a newbie, I have few questions in the first example:
    - Line 8: Is "const" necessary?
    - Line 12: Why do we have to plus 1 for the terminator?
    - Line 21: Why do we use "\0" instead of just “0”

    • Alex

      It’s necessary if you want to be able to pass constant strings into the constructor.
      strlen() returns the length of the string without the terminator, so we have to add an extra character to ensure there’s room for the terminator.
      ‘\0’ is the null character. 0 would work as well, but I think ‘\0’ makes it clearer that we’re using this as a terminator. It’s purely stylistic.

  • Reaversword

    If I’m not wrong, the code "A destructor example" lacks from the "main" part where you create an object called "myName" and (I guess) you send the string "Alex" (assuming the are a "fixed" cout that says something as:

  • ThePixelCoder

    Hey Alex! I’m a bit confused about the first example where in the constructor you had this bit

    Could you explain how this works to me and why did you do it? Thanks.

    • Alex

      Sure. This code starts m_length at 0. It then checks to see if string[m_length] is ‘\0’ (the null terminator for the string). If so, we’re done. Otherwise, m_length is incremented and we try again. By the time we’re done with this loop, string[m_length] will be the terminator for the string, and m_length will be the index of the terminator.

  • jonas

    hi alex,
    i am confused about your first example. How does getter function - char* getString() { return m_string; } return string literal of type char "Alex" while member variable  char *m_string is the pointer that holds the adress of "A"? I would expect it to return the address of "A"…

    • Alex

      It does return just the address of “A”. However, since ‘l’, ‘e’, ‘x’, and ‘\0’ will be in sequential memory next to that ‘A’, we can use the char* pointer as a C-style string.

  • Sol

    Will this delete the dynamic memory or there will be a leak?

    • Alex

      There are four problems here:
      1) You’re dereferencing pointer m_nID, but you’ve never assigned it to point at any memory address. So you’re assigning nID to garbage memory. You probable intended to have your constructor dynamically allocate an integer for m_nID?
      2) You’re deleting m_nID, but you’ve never dynamically allocated it. This can cause bad things to happen.
      3) delete[] is meant to be used for arrays, but you’re deleting a scalar (single value). You should be using delete instead.
      4) pSimple is not being deallocated.

      My guess is that deleting pSimple is crashing because of problems 1 and 2.

  • Steiner

    Hello. I have two questions. Sorry for the long post.

    1. I tried to add into your code a bit on the section: A destructor example, just to test my understanding of this tutorial. However, when I tried to create a vector of type Class (which has a constructor and destructor that deals with dynamically allocated memory), I had errors during the run-time of my program. I am assuming that I had a double delete error since vector follows the RAII paradigm and that the vector class cleans up by itself? I pasted the source code just to avoid any misunderstandings that I am making. I commented the section of code where the error is coming from.

    When I try to uncomment the code, that’s where I encounter the run-time error.

    2. I apologize in advance for this but the following code contains a mixture of C but I also tried to take some shortcuts on the code by using strdup function (from C POSIX library, to avoid writing all the copying string code again) just to see if new/delete is different from malloc/free and I still had the same error (when I try to uncomment the code below) even doing it on what it seems to be a "different way".

    I’m extremely grateful for these tutorials. Again, Thank you.

    • Alex

      First, use std::string instead of C-style strings. It’s much easier.

      Second, this looks like a deep vs shallow copying issue. You’re calling function push_back() with C-style strings instead of Items. So what C++ will do is see if it can turn the string into an Item, which it can, because you provided a constructor. So C++ will construct a temporary (anonymous) Item, and pass that to push_back(). Function push_back will make a copy.

      Here’s where things start going wrong: When Vector makes a copy of your Item, it literally copies m_length and m_label -- this means the item in the Vector is pointing to the same allocated memory as the temporary object.

      Then, the temporary Item is destroyed, which deletes m_label. This means your Item in the Vector now has a hanging pointer, and thus, runtime error.

      There are a couple ways around this:
      1) Create a copy constructor so that when Item is copied, it does a deep copy instead of a shallow copy. I talk more about these in lessons 9.11 and 9.12.
      2) Use std::string. 🙂

      • Steiner

        Hello Alex,

        Thank you very much for your reply.

        I went ahead to read the lesson 9.11 (but not 9.12 yet) and finally implemented the copy constructor to do a deep copy :). Here’s the code:

        I removed the code inside the destructor since I’m avoiding the use of dynamic memory allocation and the objects themselves will be destroyed once they go out of scope.

        I had trouble checking all the vector elements (using lesson 6.16 intro to vector and 6.12 For-each loops) and I decided to venture ahead to try out your Lesson 16.3 which talked about iterating over vector elements and that solved the problem :).

        Another interesting problem is that when I tried to explicitly initialize str::string to 0 (std::string str = 0) instead to an empty string (""), that gave me serious compilation errors:
        "…terminate called after throwing an instance of ‘std::logic_error’
          what():  basic_string::_M_construct null not valid"

        which was a first time for me to see.

        Sorry for taking too much of your time :(. I took your advice to heart and use std::string!

        I’ll be going over all your tutorials for sure since there is so much to learn.
        Again, thank you very much for your time.

  • Mili

    Hi!

    I have a question for this segment of code. How many times is destructor called?

    I guess for variables a and b, but what is with references and pointers?

    Thanks!

    • Alex

      Good question. References and pointers don’t impact the lifetime of a variable, so there is no destructor call when they go out of scope.

      So there should be only two destructor calls here -- when a and b go out of scope.

  • Ola Sh

    Hello Alex. I tried instantiating an object of MyString without any arguments, but the program failed to compile. I guess the default parameter for the class constructor does not work since it’s a pointer. I don’t really understand what may be wrong. Thanks for your help.

  • Nyap

    I’m not sure I understood RAII
    is it basically when you make a dynamically allocated variable with a constructor, and then once you’re done with it and the destructor is called it "deletes" it

  • Veer Arjun Singh

    Hey Alex I think there’s a problem in the first example on this page. In the 10th line you’ve declared string as a const but in the 14th line you’re assigning null to it.

    • Alex

      This is actually okay. string is a pointer to a const char, not a const pointer itself. That means we can’t alter the const data that the pointer is pointing to, but we can change what it is pointing at. On line 14, we simply change string to point at the string literal “”.

  • Christos

    Hi Alex,

    I wondered why not simply wrote in line 25 of the first example: m_string = string , since both are pointers (after erasing the const, from constructor’s parameter). So making a step by step debugging, I thought that the pointer "string" may point to an address in the stack, and when program leave the constructor’s scope, we want the m_string pointer, point to an address in heap.

    Is the above a reasonable explanation?

    • Alex

      Yes. For future reference, this question is in regards to this example:

      Parameter string is a pointer to some array of const chars, but we can’t assume that those chars have been allocated on the heap. If they’ve been allocated on the stack, then at some point they will die. When that happens, m_string would be left pointing to invalid memory, which would be bad.

      By making a copy of the array passed in on the heap, our class has control over the memory for that array.

      That said, I’m going to simplify this example. It’s needlessly complex to introduce destructors, and we talk more about this subject in the next chapter when we get into shallow vs deep copies. 🙂

  • Matt

    I’m not sure if I understand the section on RAII.  Under the principles of RAII, is it correct to say that an object can dynamically allocate memory upon initialization, but an object should not be dynamically allocated itself?

    • Alex

      Right. Classes can clean up after themselves because they have a destructor. If you allocate those classes on the stack, they’ll always be cleaned up properly (and resources will be released). However, if you dynamically allocate a class, and forget to delete it, then whatever resource the class was using will never be deallocated (until the program ends). So RAII says don’t dynamically allocate stuff outside of classes, because it’s too easy to accidentally end up in a situation where it doesn’t get cleaned up properly.

Leave a Comment

Put C++ code inside [code][/code] tags to use the syntax highlighter