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?