Lesson 13 • Expert
Memory Management
Master dynamic memory allocation with new/delete, understand stack vs. heap, and learn to prevent memory leaks and dangling pointers.
What You'll Learn
- ✓ Dynamic allocation with new and delete
- ✓ Stack vs. heap memory differences
- ✓ Detecting and preventing memory leaks
- ✓ Dangling pointers and how to avoid them
Stack vs. Heap — Two Kinds of Memory
Every C++ program uses two memory regions. Think of the stack as a stack of plates — you add plates on top and remove from the top. It's fast and automatic, but limited in size. The heap is like a warehouse — you can store anything of any size, but you must manage it yourself.
| Feature | Stack | Heap |
|---|---|---|
| Speed | Very fast | Slower |
| Size | Limited (~1-8 MB) | Large (GBs) |
| Lifetime | Automatic (scope) | Manual (you control) |
| Allocation | int x = 5; | int* p = new int(5); |
| Deallocation | Automatic | delete p; |
Stack vs. Heap
See the difference between stack and heap allocation
#include <iostream>
using namespace std;
void stackExample() {
int local = 10; // Stack — automatic lifetime
int arr[3] = {1, 2, 3}; // Stack array — fixed size
cout << "Stack variable: " << local << endl;
// local and arr are destroyed when function returns
}
void heapExample() {
int* p = new int(99); // Heap — manual lifetime
cout << "Heap variable: " << *p << endl;
delete p; // YOU must free it
}
int main() {
cout << "=== Stack vs Heap
...Dynamic Allocation with new and delete
Use new to allocate memory on the heap and delete to free it. For arrays, use new[] and delete[].
// Single value
int* ptr = new int(42); // Allocate and initialise
delete ptr; // Free the memory
// Array
int* arr = new int[100]; // Allocate 100 ints
delete[] arr; // Free the array
// Objects
MyClass* obj = new MyClass("hello");
delete obj; // Calls destructor then freesGolden Rule: Every new must have exactly one matching delete. Every new[] must have exactly one matching delete[].
new and delete
Allocate and free single values and arrays on the heap
#include <iostream>
using namespace std;
int main() {
// Allocate a single integer on the heap
int* ptr = new int(42);
cout << "Value: " << *ptr << endl;
cout << "Address: " << ptr << endl;
// Always delete what you new
delete ptr;
ptr = nullptr; // Prevent dangling pointer
// Allocate a dynamic array
int size = 5;
int* arr = new int[size];
for (int i = 0; i < size; i++) {
arr[i] = (i + 1) * 10;
}
cout << "\nDynami
...Memory Leaks — The Silent Bug
A memory leak happens when you allocate memory with new but never call delete. The memory stays reserved but becomes unreachable — like losing a locker key. Over time, leaks consume all available memory and crash your program.
The RAII pattern (Resource Acquisition Is Initialization) wraps heap memory inside a class. The constructor allocates, the destructor frees. When the object goes out of scope, cleanup happens automatically — no manual delete needed.
Memory Leaks & RAII
See how memory leaks happen and how RAII prevents them
#include <iostream>
using namespace std;
// BAD: This function leaks memory
void leakyFunction() {
int* data = new int[100];
// Oops! We forgot delete[] data;
// 400 bytes leaked every call
}
// GOOD: Proper cleanup
void cleanFunction() {
int* data = new int[100];
for (int i = 0; i < 100; i++) data[i] = i;
// Process data...
cout << "Sum of first 5: ";
int sum = 0;
for (int i = 0; i < 5; i++) sum += data[i];
cout << sum << endl;
delete[] da
...Dangling Pointers
Understand dangling pointers and safe deletion patterns
#include <iostream>
using namespace std;
int main() {
cout << "=== Dangling Pointer Dangers ===" << endl;
// Problem 1: Use after delete
int* p1 = new int(42);
cout << "Before delete: " << *p1 << endl;
delete p1;
// cout << *p1; // UNDEFINED BEHAVIOR!
p1 = nullptr; // Fix: nullify after delete
// Problem 2: Returning address of local variable
// int* bad() { int x = 5; return &x; } // NEVER DO THIS
// Problem 3: Double delete
int*
...Common Mistakes
⚠️ Mismatched delete: Using delete on an array allocated with new[] (or vice versa) causes undefined behavior.
⚠️ Double delete: Deleting the same pointer twice crashes your program. Always set pointers to nullptr after deleting.
⚠️ Forgetting delete in exceptions: If an exception is thrown between new and delete, the memory leaks. Use RAII or smart pointers.
⚠️ Returning address of locals: Never return a pointer to a local variable — it's destroyed when the function returns.
Pro Tips
💡 Prefer stack over heap: If the size is known at compile time and fits on the stack, don't use new.
💡 Use Valgrind: Run valgrind ./myprogram to detect memory leaks, dangling pointers, and invalid reads/writes.
💡 Smart pointers exist: In modern C++, unique_ptr and shared_ptr handle deallocation automatically. We'll cover them in the next lesson.
📋 Quick Reference
| Operation | Syntax |
|---|---|
| Allocate single | int* p = new int(val); |
| Free single | delete p; |
| Allocate array | int* a = new int[n]; |
| Free array | delete[] a; |
| Nullify after delete | p = nullptr; |
| Check null | if (p != nullptr) |
Lesson Complete!
You now understand stack vs. heap memory, dynamic allocation with new/delete, memory leaks, and dangling pointers. Next, you'll learn Move Semantics & Smart Pointers — modern C++ features that make manual memory management almost unnecessary.
Sign up for free to track which lessons you've completed and get learning reminders.