Skip to main content

Section 22.11 Destructors

In C++, a destructor is a special member function that is called when an object is destroyed. Its primary purpose is to free resources that the object may have acquired during its lifetime, such as dynamically allocated memory.
The prototype for a destructor looks like this:
~ClassName();
There is no return type, no parameters, and the name is always the same as the class name, but with a tilde (~) in front. It automatically runs when an object of the class is destroyed. This might happen because the object went out of scope (stack based variable) or was explicitly deleted (if the object was allocated on the heap). This is the place we can clean up any memory (or other restouces) that the object is responsible for.

Warning 22.11.1.

It is almost always an error to manually call the destructor. Calling it manually generally means it will run twice, once when called directly and once when it runs automatically, possibly trying to free the same memory twice.
Below is a new version of our PlayerList class with a destructor to clean up the managed array. (Normally we would not print the destructor message in a real program, that is done just for demonstration purposes.)
Listing 22.11.1.
module;

#include <iostream>
#include <string>

export module PlayerList;

using namespace std;

export class PlayerList {
private:
    string* m_players; // pointer to the array of player names
    int m_size; // number of players in the list
public:
  PlayerList(int size);

  ~PlayerList();  // Destructor

  void setPlayerName(int index, const string& name);

  void print() const;
};

PlayerList::PlayerList(int size) {
    if (size <= 0) {
        throw invalid_argument("Size must be positive");
    }
    m_size = size;
    m_players = new string[m_size]; // allocate memory for the array
}

PlayerList::~PlayerList() {
    delete[] m_players; // deallocate memory for the array
    cout << "**PlayerList destroyed and memory freed.**" << endl;
}

void PlayerList::setPlayerName(int index, const string& name) {
    if (index < 0 || index >= m_size) {
        throw out_of_range("Index out of range");
    }
    m_players[index] = name; // set the player name at the given index
}

void PlayerList::print() const {
    cout << "Player List: ";
    for (int i = 0; i < m_size; ++i) {
        cout << m_players[i] << " ";
    }
    cout << endl;
}
Note that the only thing it needs to do is delete the array that is being tracked by the pointer m_players. The memory for the PlayerList variables themselves is automatically managed by C++ and does not need to be deleted manually.
The pList variable contains a pointer to the array of player names
Figure 22.11.2. The heap based array that m_players points to needs to be cleaned up in the destructor.
Now, when we run the same main program, we should see that the memory is properly freed. The destructor message should be printed when the PlayerList object is destroyed at the end of main. And AddressSanitizer should now not identify any leaks.
Listing 22.11.3.
The destructor ends whenever an object goes out of scope. In the program above, that was at the end of main. In the new program below, we have a separate function testPlayerList() that creates a PlayerList object. When testPlayerList() ends, the PlayerList object is destroyed, and we see the destructor message. testPlayerList() is called twice from main, so you will see two destructor messages, one at the end of each function call.
Listing 22.11.4.

Note 22.11.2.

Destructors should always be virtual in base classes to ensure proper cleanup of derived classes. We will not be mixing the ideas of inheritance and container classes, and so this will not be an issue for us. But if you are writing a class that you think might be extended, it is best to mark the destructor as virtual.

Checkpoint 22.11.1.

We want to add a destructor to the NumberList class. It manages a dynamic array of integers. Examine the members and decide what needs to be deleted. Then build the function as it would appear when defined outside the class.
classDiagram
    class NumberList {
    -m_numbers : int&ast;
    -m_size : int
    -m_description : string
    }
        
      
You have attempted of activities on this page.