Destruction for Custom Classes: Destructors
So far, we've managed to allocate space all over the heap!
But remember the rule: Any time you allocate space with
new
, you should deallocate it withdelete
!
An object's destructor is called when the object is destroyed. Since destruction will take the names of the object and all of its data members out of scope, it's our last chance to clean up any mess that object has made in memory!
Like constructors, destructors can be synthesized by the compiler. If we don't specify what should happen in a destructor, the compiler's synthesized one will go through and destroy each of the object's data members in turn.
Our data members are all primitive types (pointers are a primitive type), and their destructors will "do nothing" to their values. As a result, the synthesized destructor will end up doing nothing at all for our class. Which means we're going to end up with a memory problem…
Writing a Custom Destructor
So we have an array full of
Cow*
s on the heap, and eachCow*
points to aCow
, also on the heap.And we're going to have to delete all of that.
That sounds familiar…. We wanted to do something similar with
Elephant
s in Week 5 Lesson 2?Yup! And here we are doing it! We're going to have two big categories of things that we need to destroy and deallocate:
- The individual
Cow
s on the heap - The array of
Cow*
s on the heap
- The individual
Here's the start of a Barn
destructor:
1| Barn::~Barn() {
2| // Destroy and deallocate the individual Cows on the heap
3| for (size_t i = 0; i < cowCount_; ++i) {
4| _______;
5| }
6|
7| // Destroy and deallocate the array of Cow pointers
8| _______;
9| }
Hint: Remember that we need to give delete
the address of the memory that needs to be destroyed and deallocated. So delete
wants a pointer of some kind! But it also needs to be a pointer that originally came out of new
.
Our destructor for the Barn
class now looks like
Barn::~Barn() {
// Destroy and deallocate the individual Cows on the heap
for (size_t i = 0; i < cowCount_; ++i) {
delete residentCows_[i];
}
// Destroy and deallocate the array of Cow pointers
delete[] residentCows_;
}
You can check out a runnable version of this code with a working default constructor and destructor using the button below:
Alternatively, you can write the destructor using the start/past-the-end pointer approach (that we saw in Week 5 Lesson 1):
Barn::~Barn() {
// Destroy and deallocate the individual Cows on the heap
for (Cow** p = residentCows_; p < residentCows_ + cowCount_; ++p) {
delete *p;
}
// Destroy and deallocate the array of Cow pointers
delete[] residentCows_;
}
This latter version is shown in the video below.
Phew! We've done a lot. Let's head up to the parent page and see what we've learned, and maybe take a break.
(When logged in, completion status appears here.)