C++

Memory Management

C++ has its own version of C's malloc/free — new and delete — with the exact same manual-matching-pair risk. Smart pointers are C++'s real answer: RAII, applied directly to raw memory, making "forgot to free it" a non-issue rather than a discipline problem.

Quick reference
What it is
new/delete: C++'s manual heap allocation, analogous to malloc/free. Smart pointers: classes that own a heap allocation and free it automatically via their destructor.
Mental model
A smart pointer is a small wrapper object that acts like a raw pointer for everyday use, but also holds a "when I die, free what I point to" promise — the same RAII trick applied to memory specifically.
Key numbers
std::unique_ptr has zero performance overhead versus a raw pointer; std::shared_ptr has a small overhead for its internal reference count.
Reach for it when
Any time you'd reach for new — modern C++ practice treats a smart pointer as the default, and a raw owning pointer as the rare exception.

new and delete

int *p = new int(42);   // allocate one int on the heap, initialized to 42
std::cout << *p << std::endl;   // 42
delete p;                 // free it — required, exactly like C's free()

int *arr = new int[10];   // allocate an array
delete[] arr;               // matching array-delete — required for array allocations

This has exactly the same failure mode as C's malloc/free: forget the matching delete and the memory leaks for the life of the program; call delete twice on the same pointer and the behavior is undefined. See Embedded C's Dynamic Memory for the full picture of why manual allocation is risky in the first place.

std::unique_ptr

std::unique_ptr owns a heap allocation exclusively — exactly one unique_ptr can own a given object at a time, and it's freed automatically the instant the unique_ptr itself goes out of scope:

#include <memory>

void useBuffer() {
    std::unique_ptr<int[]> buffer(new int[100]);
    buffer[0] = 42;                       // used exactly like a raw pointer
    std::cout << buffer[0] << std::endl;  // 42
}   // buffer goes out of scope HERE — the array is freed automatically, no delete needed

This is precisely the RAII pattern from Constructors, Destructors & RAII, applied directly to a heap allocation — there's no delete anywhere in this function because there doesn't need to be one.

std::shared_ptr

std::shared_ptr allows multiple owners of the same allocation, tracked with an internal reference count — the memory is only freed once the last owning shared_ptr goes out of scope:

std::shared_ptr<int> a = std::make_shared<int>(42);
std::cout << a.use_count() << std::endl;   // 1

{
    std::shared_ptr<int> b = a;             // b shares ownership with a
    std::cout << a.use_count() << std::endl;   // 2
}   // b goes out of scope, but the int is NOT freed — a still owns it

std::cout << a.use_count() << std::endl;   // back to 1
// the int is finally freed when a itself goes out of scope

Ownership, visually

A unique_ptr has exactly one owner pointing at the heap allocation; a shared_ptr can have several owners, tracked by a reference count, and the allocation is freed only when the count reaches zero unique_ptr heap object shared_ptr a shared_ptr b heap object refcount = 2
A unique_ptr's ownership is exclusive and simple; a shared_ptr's reference count is what lets multiple owners exist safely, at the small cost of tracking that count.

Real-world applications

Gotchas

Field notes