Smart Pointers: unique_ptr and shared_ptr

A smart pointer is an object that holds a pointer and uses RAII to delete it automatically. With smart pointers you almost never need to write delete again. They live in <memory>.

unique_ptr: one owner

A unique_ptr is the only owner of its object. When the unique_ptr goes away, the object is deleted:

#include <iostream>
#include <memory>
#include <string>
using namespace std;

class Robot {
    string name;
public:
    Robot(string n) : name(n) { cout << name << " switched on\n"; }
    ~Robot() { cout << name << " switched off\n"; }
    void wave() const { cout << name << " waves\n"; }
};

int main() {
    unique_ptr<Robot> r = make_unique<Robot>("R2");
    r->wave();
    cout << "End of main\n";
    return 0;
}                    // r is destroyed here, and it deletes the Robot

Output

R2 switched on
R2 waves
End of main
R2 switched off

A unique_ptr can't be copied (there can only be one owner), but ownership can be handed over with move:

#include <iostream>
#include <memory>
using namespace std;

int main() {
    unique_ptr<int> a = make_unique<int>(42);
    unique_ptr<int> b = move(a);           // b owns it now, a is empty
    cout << (a == nullptr ? "a is empty" : "a has a value") << "\n";
    cout << "b holds " << *b << "\n";
    return 0;
}

Output

a is empty
b holds 42

shared_ptr: many owners

A shared_ptr can be copied. All copies share the object, and it is deleted when the last one goes away. use_count() tells you how many owners there are:

#include <iostream>
#include <memory>
#include <string>
using namespace std;

struct Song {
    string title;
    Song(string t) : title(t) {}
    ~Song() { cout << "Deleting " << title << "\n"; }
};

int main() {
    shared_ptr<Song> s1 = make_shared<Song>("Imagine");
    cout << "Owners: " << s1.use_count() << "\n";
    {
        shared_ptr<Song> s2 = s1;          // a second owner
        cout << "Owners: " << s1.use_count() << "\n";
    }
    cout << "Owners: " << s1.use_count() << "\n";
    cout << "Now playing " << s1->title << "\n";
    return 0;
}

Output

Owners: 1
Owners: 2
Owners: 1
Now playing Imagine
Deleting Imagine

Polymorphism with smart pointers

A vector of unique_ptr to a base class is the modern way to keep different kinds of objects together:

#include <iostream>
#include <memory>
#include <vector>
using namespace std;

struct Shape {
    virtual double area() const = 0;
    virtual ~Shape() {}
};

struct Square : Shape {
    double s;
    Square(double side) : s(side) {}
    double area() const override { return s * s; }
};

struct Rect : Shape {
    double w, h;
    Rect(double width, double height) : w(width), h(height) {}
    double area() const override { return w * h; }
};

int main() {
    vector<unique_ptr<Shape>> shapes;
    shapes.push_back(make_unique<Square>(3));
    shapes.push_back(make_unique<Rect>(2, 5));
    for (const auto& s : shapes) {
        cout << s->area() << "\n";
    }
    return 0;                // every shape is deleted automatically
}

Output

9
10

Remember: Use unique_ptr by default. Use shared_ptr only when several parts of the program really need to share ownership. Avoid raw new/delete.

HOME LABS COMMUNITY DASHBOARD