Elephant Parade, Part 4: Memory Leaks
Meh.
What do you mean, "meh?" Didn't we solve the problem?
I say "meh" to you again! The user needs to know how many elephants they want to add beforehand.
Okay, I can see how that could be inconvenient.
I think you should be able to just keep adding elephants until you want to stop.
All right, everyone. Back to the drawing board!
"Resizing" The Array
Here's an idea:
- Pick an initial size for the array.
- Keep adding
Elephant
s into the array as they arrive. - When we run out of space, allocate a new, bigger array.
- Copy the contents over to the new array and continue.
That way we can always add more
Elephant
s.I approve this plan.
Here's some code that does that. The reallocation part is highlighted.
int main() {
constexpr size_t ELEPHANTS_TO_ADD = 2;
size_t elephantCapacity = ELEPHANTS_TO_ADD;
Elephant* elephants = new Elephant[ELEPHANTS_TO_ADD];
string anotherElephant = "y";
size_t numElephants = 0;
while (anotherElephant == "y") {
++numElephants;
cout << "Please enter elephant " << numElephants << endl;
string name;
cout << "Name: ";
cin >> name;
int age;
cout << "Age: ";
cin >> age;
Elephant el{name, age};
if (numElephants > elephantCapacity) {
// We ran out of space, so make a bigger array
Elephant* newElephants = new Elephant[elephantCapacity + ELEPHANTS_TO_ADD];
// Now copy the contents
for (size_t i = 0; i < elephantCapacity; ++i) {
newElephants[i] = elephants[i];
}
// Now start using the new array
elephants = newElephants;
elephantCapacity += ELEPHANTS_TO_ADD;
}
elephants[numElephants - 1] = el;
cout << endl << "Another elephant (y/n)? ";
cin >> anotherElephant;
cout << endl;
}
// We'll just assume this works
sortElephantsByName(elephants, elephants + numElephants);
cout << "The elephants are parading!" << endl;
for (size_t i = 0; i < numElephants; ++i) {
cout << elephants[i].getName() << " (" << elephants[i].getAge() << ")" << endl;
}
return 0;
}
Draw a diagram to visualize how this version works. Work through adding at least 3 Elephant
s, so you can see the "resize" happen.
Key Points:
- The arrays we create stay in memory.
- The more times we resize, the more arrays are lying around.
- Even worse, we lose all pointers to those arrays.
- With no pointer, we can never access them again.
- This situation is called a memory leak.
Memory Leaks
As we saw above, a memory leak is when we have allocated memory on the heap and lost all pointers to that memory. Without pointers, we lose access to what was in that memory, but we're still occupying memory on the system, which we won't get back until our program terminates.
Remember when we said that a pointer is like a treasure map and the data is like the treasure?
Well a memory leak is like losing the map. The treasure's still out there, but you'll never find it.
Yarr. I hate when that happens, matey. Aye…
On a small scale, memory leaks don't cause many practical problems. But when you have a leak in a loop (as in our example program), the memory usage of the program can just grow and grow the longer it runs.
Have you ever noticed that when you leave your web browser open for a really long time, it uses more and more RAM? And then when you restart it, even with all the same tabs open, it uses less? It probably has memory leaks!
Most web browsers seem to have modest memory leaks these days, but there have been some really nasty memory leaks in past versions of most major web browsers. Memory leaks in browsers become news because people tend to interact with their web browser a lot, over long periods of time.
Just like any other incorrect behavior, it's our responsibility to prevent memory leaks in our programs.
So, how do we do that?
We need to learn how to deallocate memory on the heap.
And then we need to be careful about deallocating memory that we are done with.
(When logged in, completion status appears here.)