A destructor is another special kind of class member function that is executed when an object of that class is destroyed. They are the counterpart to constructors. When a variable goes out of scope, or a dynamically allocated variable is explicitly deleted using the delete keyword, the class destructor is called (if it exists) to help clean up the class before it is removed from memory. For simple classes, a destructor is not needed because C++ will automatically clean up the memory for you. However, if you have dynamically allocated memory, or if you need to do some kind of maintenance before the class is destroyed (eg. closing a file), the destructor is the perfect place to do so.
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.
Let’s take a look at a simple string class that uses a destructor:
class MyString
{
private:
char *m_pchString;
int m_nLength;
public:
MyString(char *pchString="")
{
// Find the length of the string
// Plus one character for a terminator
m_nLength = strlen(pchString) + 1;
// Allocate a buffer equal to this length
m_pchString = new char[m_nLength];
// Copy the parameter into our internal buffer
strncpy(m_pchString, pchString, m_nLength);
// Make sure the string is terminated
m_pchString[m_nLength-1] = '\\0';
}
~MyString() // destructor
{
// We need to deallocate our buffer
delete[] m_pchString;
// Set m_pchString to null just in case
m_pchString = 0;
}
char* GetString() { return m_pchString; }
int GetLength() { return m_nLength; }
};
Let’s take a look at how this class is used:
int main()
{
MyString cMyName("Alex");
std::cout << "My name is: " << cMyName.GetString() << std::endl;
return 0;
} // cMyName destructor called here!
This program produces the result:
My name is: Alex
On the first line, we instantiate a new MyString class and pass in the C-style string “Alex”. This calls the constructor, which dynamically allocates memory to hold the string being passed in. We must use dynamic allocation here because we do not know in advance how long of a string the user is going to pass in.
At the end of main(), cMyName goes out of scope. This causes the ~MyString() destructor to be called, which deletes the buffer 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:
class Simple
{
private:
int m_nID;
public:
Simple(int nID)
{
std::cout << "Constructing Simple " << nID<< endl;
m_nID = nID;
}
~Simple()
{
std::cout << "Destructing Simple" << m_nID << endl;
}
int GetID() { return m_nID; }
};
int main()
{
// Allocate a Simple on the stack
Simple cSimple(1);
std::cout << cSimple.GetID() << std::endl;
// Allocate a Simple dynamically
Simple *pSimple = new Simple(2);
std::cout << pSimple->GetID() << std::endl;
delete pSimple;
return 0;
} // cSimple goes out of scope here
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 cSimple was not destroyed until the end of main().
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 easy to use.
8.7 — The hidden “this†pointer
|
Index
|
8.5 — Constructors
|
8.7 — The hidden “this†pointer
Index
8.5 — Constructors
Hello,
can I call the destructor explicitly?
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
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.
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).
In the above code, shouldn’t:
delete m_pchString;
be:
delete m_pchString[];
[ Almost. It should be
delete[] m_pchString. I’ve been programming C++ for 10 years and I _still_ forget to use array delete instead of normal delete with arrays. It’s one of the things I really dislike about C++. Great catch. -Alex ]std::cout << “Destructing Simple” << nID<< endl;
should be
std::cout << “Destructing Simple” << m_nID<< endl;
Actually it’s okay as is, because nID was passed in as a parameter.
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!
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.
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)
Thanks,
QUOTE: assuming you don’t exit() early
ah, is there an easy way around this? to call the destructor on an exit() call?