Step 1 of 5
unique_ptr
In C, every malloc needs exactly one free, and forgetting it (or doing it twice) is a bug. C++'s raw new and delete have the same problem. A smart pointer is a small object that owns a heap object and deletes it for you in its destructor. It's RAII applied to heap memory.
std::unique_ptr<T> (from <memory>) is the one to use by default. It has one owner, and it costs nothing extra at run time compared with a raw pointer.
#include <iostream>
#include <memory>
#include <string>
#include <utility>
struct Robot {
std::string name;
int battery;
Robot(std::string n, int b) : name(n), battery(b) { std::cout << name << " built\n"; }
~Robot() { std::cout << name << " scrapped\n"; }
};
int main() {
auto r = std::make_unique<Robot>("R2", 80); // arguments go to Robot's constructor
r->battery -= 30; // -> works like a raw pointer
std::cout << (*r).name << " at " << r->battery << "%\n";
{
auto temp = std::make_unique<Robot>("C3", 100);
std::cout << "inner block ends\n";
} // temp deletes its Robot here
std::cout << "main ends\n";
} // r deletes its Robot here
R2 built
R2 at 50%
C3 built
inner block ends
C3 scrapped
main ends
R2 scrapped
How it works
std::make_unique<T>(args...)allocates aTon the heap, passesargsto its constructor, and returns aunique_ptr<T>owning it. It's the only line where the allocation happens, and there's never a matchingdeletein your code.p->memberand*pwork exactly like a raw pointer.- When the
unique_ptrgoes out of scope, its destructor deletes the object. The output shows each robot scrapped at the end of its own block. autosaves writingstd::unique_ptr<Robot>twice.
Common mistakes
- Writing
std::unique_ptr<Robot> r(new Robot(...)). It works, butmake_uniqueis shorter, names the type only once, and keeps a barenewout of your code entirely. (Before C++17 it also prevented a subtle leak whennewappeared inside a function call's arguments.) - Creating a
unique_ptrfor something that could just be a normal local variable. Use the heap only when you need it: the object must outlive the scope, it's very large, or it's polymorphic.
Your turn: create the object with make_unique and access it through the pointer.