Destructors

What's a destructor?

As we have seen, your code must explicitly call delete to return memory used for dynamically allocated variables to the heap.

But what if the dynamically allocated variable is embedded in a class? The user of the class doesn't know there's dynamically allocated memory and couldn't use delete even if he did since the pointer in the class would be a private data member.

To address this problem, each class has a special member function called a destructor. A class' destructor is called whenever an object of the class goes out of scope. The name of the destructor is the same as the name of the class preceded by a tilde ( ~ ). Like a constructor, the destructor has no return type. Only one destructor is permitted for a class. Destructors have no parameters.

class Car { public: // multiple constructors Car( ); Car( const sting& color, int miles); // ONE destructor ~Car ( ); // other public stuff private: string m_color; int m_mileage; }; // The code in Car.cpp Car::~Car( ) { // code here }

Why haven't we seen this before

A destructor is used to free any resources used by the class such as files, CD drives, tape drives, connections to other computers, and of course dynamically allocated memory.

The compiler provides a destructor for every class if we do not write one ourselves. Since we haven't used any dynamically allocated memory until now, the destructor provided by the compiler has been sufficient.

A modified Car

Suppose you decided that the private data of your Car class should be dynamically allocated. The private data members would then be pointers. class Car { public: // Constructor Car( const string& color, int miles); // Destructor ~Car ( ); // other public methods private: string *m_color; int *m_mileage; }; The Car's constructor would allocate and initialize the heap memory for color and mileage. The destructor would deallocate the memory. // Car constructor Car::Car( const string& color, int miles ) { m_color = new string; *m_color = color; m_mileage = new int( miles ); } // Car's destructor Car::~Car( ) { delete m_color; delete m_mileage; }

Security Issues

One way in which hackers gain valuable information is by writing programs that examine memory. One way we can thwart their attempts is to clean up memory to the fullest extent possible. In particular this means that we can overwrite sensitive data and set pointers to 0 when they are no longer needed.

For example, Car's destructor might be better written as

Car::~Car ( ) { // set the color to the empty string *m_color = ""; // set the mileage to 0 *m_mileage = 0; // delete the memory and reset the pointers delete m_color; delete m_mileage; m_color = 0; m_mileage = 0; }

Destructors and Aggregation

When we first discussed aggregation, we saw how the constructor of each data member object was automatically called, or could be called using the member initialization list. What about destructors.

This is another case of "what you want to happen does happen".

When an object is destroyed, the destructor for each of its data members which are also objects is automatically invoked too. Each object takes care of itself. No special code is needed in a class' destructor.

Point for discussion: What is the order in which the destructors are invoked? How does this compare to the order in which constrcutors are called?