Intermediate 12 min

Memory Leaks and Management

Understand memory leaks, how to detect them, and best practices for managing dynamic memory safely

Learn how to identify and prevent memory leaks that can crash your application hours after launch.

A Simple Example

#include <iostream>

void leakyFunction() {
    int* numbers{new int[1000]};
    // Oops! Forgot to delete[] numbers
    // This memory is now lost forever (until program ends)
}

void properFunction() {
    int* numbers{new int[1000]};

    // Use the array...
    numbers[0] = 42;

    delete[] numbers;  // Memory properly released
    numbers = nullptr; // Good practice: prevent dangling pointer
}

int main() {
    // Call leakyFunction 1000 times
    for (int i{0}; i < 1000; ++i) {
        leakyFunction();  // Leaking 4KB each call = 4MB total leaked!
    }

    // Call properFunction safely
    for (int i{0}; i < 1000; ++i) {
        properFunction(); // No leaks - memory reused
    }

    return 0;
}

Breaking It Down

Memory Leaks Explained

  • What happens: Allocated memory is never freed, staying reserved until program exit
  • Impact: Each leak consumes RAM permanently - thousands of leaks can consume gigabytes
  • Detection: Memory usage grows continuously even when program appears idle
  • Remember: Every new must have a matching delete, every new[] needs delete[]

Proper Cleanup with delete

  • What it does: delete returns memory to the operating system for reuse
  • Array cleanup: Use delete[] for arrays allocated with new[]
  • After deletion: Set pointer to nullptr to prevent accidental reuse
  • Remember: Deleting a nullptr is safe and does nothing

The Destructor Pattern

  • What it does: Destructors automatically clean up resources when objects go out of scope
  • RAII principle: Resource Acquisition Is Initialization - tie cleanup to object lifetime
  • Benefit: Cleanup happens automatically, even during exceptions
  • Remember: This is the foundation of safe C++ resource management

Modern Alternatives

  • Smart pointers: std::unique_ptr and std::shared_ptr automatically manage memory
  • Containers: Use std::vector instead of raw arrays for automatic cleanup
  • Best practice: Prefer smart pointers over raw new/delete in modern C++
  • Remember: Raw pointers should only be used for non-owning references

Why This Matters

  • Memory leaks are silent killers that slowly consume all available RAM, leading to crashes hours or days after launch.
  • Professional C++ developers spend significant time preventing and debugging memory issues.
  • Understanding memory management is what separates hobbyist programmers from production-ready developers.

Critical Insight

The destructor is your cleanup crew! When you properly implement destructors, they automatically clean up memory when objects are deleted or go out of scope. This is called RAII (Resource Acquisition Is Initialization) - resources are tied to object lifetime.

It's like a self-cleaning oven - you don't manually clean it, it happens automatically. This is why smart pointers are so powerful - their destructors automatically delete memory, making leaks nearly impossible.

Best Practices

Always pair new with delete: Every allocation needs cleanup. Use delete for new, delete[] for new[].

Set pointers to nullptr after deletion: This prevents dangling pointer bugs. Deleting nullptr is safe.

Prefer smart pointers: Use std::unique_ptr and std::shared_ptr instead of raw new/delete in modern C++.

Use RAII: Put cleanup in destructors so it happens automatically, even during exceptions.

Use containers over arrays: std::vector manages memory automatically and is safer than raw arrays.

Common Mistakes

Double Delete: Calling delete twice on the same pointer causes undefined behavior (usually a crash).

Mixing new/delete Forms: Using delete instead of delete[] for arrays or vice versa causes undefined behavior.

Returning Local Pointers: Returning a pointer to a local variable that goes out of scope creates a dangling pointer.

Forgetting to delete: Memory leaks accumulate, especially in loops. A small leak repeated thousands of times becomes gigabytes.

Debug Challenge

This function leaks memory. Click the highlighted line to add proper cleanup:

1 #include <iostream>
2
3 void processData() {
4 int* data{new int[100]};
5 data[0] = 42;
6 std::cout << data[0] << "\n";
7 }

Quick Quiz

  1. What happens if you forget to delete allocated memory?
Memory leak - the memory stays allocated until program ends
The compiler gives an error
The memory is automatically freed after 60 seconds
  1. Which is correct for cleaning up an array?
delete[] arr;
delete arr;
free(arr);
  1. What should you do after deleting a pointer?
Set it to nullptr
Nothing, deletion is complete
Delete it again to be sure

Practice Playground

Time to try out what you just learned! Play with the example code below, experiment by making changes and running the code to deepen your understanding.

Lesson Progress

  • Fix This Code
  • Quick Quiz
  • Practice Playground - run once