C++
Completed
-
Section 1: Getting Started
-
Section 2: Core Syntax
-
Section 3: Object-Oriented C++
-
Section 4: Memory Management
-
Section 5: Templates and Generic Programming
-
Section 6: The Standard Template Library
-
Section 7: Modern C++ Features
-
Section 8: Error Handling
-
Section 9: Multithreading
-
Section 10: Operator Overloading and Type Conversion
-
Section 11: Advanced Topics
-
Section 12: Tooling and Build Systems
-
Section 13: Design Patterns in C++
-
Section 14: Interfacing with C and Systems Programming
-
Section 15: Networking and IPC Basics
-
Section 16: Graphics and Game Programming Basics
-
Section 17: The Boost Libraries
-
Section 18: Data Structures and Algorithms in C++
-
Section 19: Practical Projects
-
Section 20: More Concurrency Patterns
-
Section 21: More OOP and Design Practice
-
Section 22: File I/O and Streams
-
Section 23: More Standard Library
-
Section 24: Practice Exercises
-
Section 25: Interview and Algorithm Practice
-
Section 26: Compiler and Language Internals
-
Section 27: GUI and Application Frameworks Overview
-
Section 28: Testing and Quality Practices
-
Section 29: Numerics Library
-
Section 30: Concepts Library (C++20)
-
Section 31: Ranges Library (C++20) In Depth
-
Section 32: More Utility Library
51: Avoiding Memory Leaks and Dangling Pointers
How do I stop a pointer from pointing to garbage after I've deleted the object?
This is the classic "dangling pointer" problem. When you call delete ptr;, you're telling the operating system, "I'm done with the memory at this address." However, the variable ptr itself doesn't magically disappear or reset; it still holds that memory address. If you accidentally try to use ptr again, you're accessing memory you no longer own. This might crash immediately, or worse, it might "work" for a while and then corrupt your data randomly.
The simplest fix is a habit: immediately set the pointer to nullptr after deleting it.
GameCharacter* player = new GameCharacter("Aragorn");
// ... some game logic ...
delete player;
player = nullptr; // Now it's safe.
if (player != nullptr) {
player->attack(); // This block won't execute, preventing a crash.
}
I've spent hours debugging "heisenbugs" because I forgot this one line. In C++, checking for nullptr is your primary safety net when dealing with raw pointers.
I keep forgetting to call delete. Is there a way to make the compiler handle the cleanup?
Yes, and in modern C++, this is exactly how we avoid memory leaks. You should rarely be using new and delete manually. Instead, we use Smart Pointers. The most common one is std::unique_ptr. It uses a concept called RAII (Resource Acquisition Is Initialization), which basically means the memory is tied to the lifetime of the pointer object itself.
Think of it like a contract: when the unique_ptr goes out of scope (like at the end of a function), it automatically calls delete for you. No more forgetting to clean up.
#include <memory>
void spawnEnemy() {
// No 'new' keyword needed here if we use make_unique
std::unique_ptr<Enemy> monster = std::make_unique<Enemy>("Goblin");
monster->roar();
// No delete needed! Memory is freed automatically when the function ends.
}
If you need multiple parts of your code to "share" ownership of an object, you can use std::shared_ptr. It keeps a reference count and only deletes the object when the last pointer to it is destroyed. Just be careful—if two shared_ptrs point to each other, you get a circular reference, and you're right back to having a memory leak.
What actually happens if I delete the same pointer twice?
This is called a "double free," and it's a recipe for a security vulnerability or a hard crash. When you call delete, the memory manager marks that block as available. If you call delete on that same address again, you're trying to free memory that might have already been reassigned to a completely different part of your program.
Here is the scary part: delete nullptr; is perfectly safe and does absolutely nothing. This is why the player = nullptr; trick I mentioned earlier is so powerful. If you accidentally call delete on a pointer that has already been deleted and nulled, the program just keeps running smoothly.
GameCharacter* boss = new GameCharacter("Smaug");
delete boss;
// delete boss; // CRASH! Double free.
boss = nullptr;
delete boss; // Perfectly safe. No crash.📋 Practical Task
Fixing the Leaky Game Inventory System
You've been handed a piece of legacy code for a game inventory system. The current implementation uses raw pointers and has a massive memory leak because items are added to the inventory but never deleted when the inventory is cleared. Additionally, there is a risk of dangling pointers when items are removed.
Your Task:
- Refactor the
Inventoryclass to usestd::unique_ptr<Item>instead of rawItem*pointers. - Remove the manual
deletecalls in the destructor, as the smart pointers will now handle this automatically. - Ensure that the
removeItemmethod properly handles the memory release (which should now happen automatically when theunique_ptris removed from the container).
Starter Code:
#include <iostream>
#include <vector>
#include <string>
#include <memory>
class Item {
public:
std::string name;
Item(std::string n) : name(n) { std::cout < "Created " < name < "\n"; }
~Item() { std::cout < "Destroyed " < name < "\n"; }
};
class Inventory {
std::vector<Item*> items; // Change this to unique_ptr
public:
void addItem(std::string name) {
items.push_back(new Item(name)); // Refactor to make_unique
}
void clearInventory() {
for (auto item : items) {
delete item;
}
items.clear();
}
~Inventory() {
clearInventory();
}
};There are no comments for now.