Class destructor

What is a destructor?

The destructor is a special method that is called automatically when an object of a class is destroyed (When its life span is over or, when using dynamic memory allocation, if it is manually deleted). The same way the constructors call the constructors of the member objects of the class it belongs to, the destructors call their destructor. It does not return any value nor take arguments, so it can not be overloaded.

Defining the destructor

Destructors are declared and defined the same way as constructors are, except that their name is prefixed with ~.

Character.hpp

1
2
3
4
5
6
7
8
9
10
11
12
#ifndef CHARACTER_HPP #define CHARACTER_HPP #include <iostream> class Character { public: ~Character(); }; #endif

Character.cpp

1
2
3
4
5
6
#include "Character.hpp" Character::~Character() { std::cout << "The object is destroyed." << std::endl; }

main.cpp

1
2
3
4
5
6
7
8
9
10
11
12
#include "Character.hpp" int main() { std::cout << "Before the object is created." << std::endl; Character character; std::cout << "After the object is created." << std::endl; return 0; }

In the example above, when the life span of the object character is over (At the end of the braces {} of the function main), its destructor is called, which prints the string "The object is destroyed." to the console.

Managing dynamic memory allocation in classes

Destructors are especially useful when using dynamic memory allocation. We usually allocate the memory in the constructor of the class and free it in its destructor. That way, we do not forget to free it as it is automatically done when the object reaches the end of its life span.

Example of dynamic memory allocation handled inside a class:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#include <iostream> #include <stdlib.h> class AutoMemAlloc{ public: AutoMemAlloc(unsigned nbBytes) { _data = (char*)malloc(nbBytes); std::cout << nbBytes << " bytes allocated!\n"; } ~AutoMemAlloc() { if(_data != 0) { free(_data); std::cout << "Memory freed!\n"; } } private: char *_data; }; int main() { std::cout << "Before the object is created." << std::endl; AutoMemAlloc autoMemAlloc(567); std::cout << "After the object is created." << std::endl; return 0; }

Destructor call order of member objects

The constructor call the constructors of the member objects and then execute the code in its definition. For the destructor, it is the opposite. It executes its code and then call the destructors of the member objects of the class it belongs to. Also, while the member objects are constructed in the same order they are defined, they are destroyed in the reverse order. That means that the last member object to be defined is the first one to have its destructor called.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#include <iostream> class A { public: ~A() { std::cout << "Destructor of the class A called." << std::endl; } }; class B { public: ~B() { std::cout << "Destructor of the class B called." << std::endl; } }; class C { public: ~C() { std::cout << "Destructor of the class C called." << std::endl; } private: A _a; B _b; }; int main() { C c; return 0; }