std::unique_ptr
In C, a heap allocation is a loose promise: you call malloc() or new and you must, somewhere, exactly once, call the matching free() or delete — and every early return or exception in between is a chance to forget and leak. std::unique_ptr is a tiny RAII object that holds a single owning pointer and deletes it automatically in its destructor. It is the modern, leak-proof replacement for owning raw pointers, and crucially it costs essentially nothing extra at runtime over a raw pointer.
The defining property is unique ownership: a std::unique_ptr cannot be copied, only moved. That single restriction encodes 'exactly one owner' directly into the type system — there is never a second unique_ptr to the same object, so there is never a double-delete and never ambiguity about who frees it. Moving a unique_ptr transfers ownership: the source is left holding nullptr and the destination now owns the object. You create one with std::make_unique<T>(args...), which allocates the object and wraps it in one step; when the unique_ptr is destroyed (or reset, or reassigned), it calls delete on the managed object for you.
Why it matters: unique_ptr is the default smart pointer and the right tool whenever there is a clear single owner — which is most of the time. It is the same size as a raw pointer (for the default deleter) and adds no reference counting, so it embodies the zero-overhead principle. The honest caveats: it owns, but you can still get a non-owning raw view with .get() to pass to APIs that don't take ownership; releasing ownership entirely (.release()) hands you back a raw pointer that you must now delete yourself; and a unique_ptr to an array needs the array form std::unique_ptr<T[]> so it calls delete[] and not delete.
auto p = std::make_unique<Widget>(args); use(*p); // no delete needed; Widget is freed when p leaves scope, even on an exception
make_unique allocates and wraps in one step; the destructor of p calls delete for you exactly once.
unique_ptr is move-only by design: trying to copy it is a compile error, which is the feature, not a limitation — it is the type system refusing to let two owners exist. Prefer make_unique over new so you never write delete and so allocation is exception-safe.