CS253: Software Development with C++

Spring 2021

Smart Pointers

Show Lecture.SmartPointers as a slide show.

CS253 Smart Pointers

Overview

The Problem

auto p = new Loud;
if (getuid() != 0) {
    cerr << "Wrong user!\n";   // Heckendorn weeps.
    return 1;
}
delete p;
Loud::Loud()
Wrong user!

Three kinds of smart pointers

  1. unique_ptr if the thing has one owner
  2. shared_ptr if the thing has several owners
  3. weak_ptr for voyeurs & lurkers
  4. auto_ptr for people who use obsolete features

auto_ptr

unique_ptr

unique_ptr example #1

unique_ptr<Loud> p(new Loud);
if (getuid() != 0) {
    cerr << "Wrong user!\n";
    return 1;
}
// don’t need to delete
Loud::Loud()
Wrong user!
Loud::~Loud()

unique_ptr example #2

void foo() {
    unique_ptr<Loud> p(new Loud);
    if (getuid() != 0)
        throw logic_error("Wrong user!");
}

int main() {
    try {
        foo();
    }
    catch (const exception &e) {
        cerr << e.what() << '\n';
    }
    return 0;
}
Loud::Loud()
Loud::~Loud()
Wrong user!

shared_ptr

shared_ptr example

shared_ptr<Loud> p(new Loud);
cout << p.use_count() << '\n';
{
    cout << p.use_count() << '\n';
    auto q=p;
    cout << p.use_count() << '\n';
    cout << q.use_count() << '\n';
}
cout << p.use_count() << '\n';
Loud::Loud()
1
1
2
2
1
Loud::~Loud()

vector of shared_ptr example

vector<shared_ptr<Loud>> a;
{
    vector<shared_ptr<Loud>> b;
    b.push_back(shared_ptr<Loud>(new Loud('x')));
    b.push_back(shared_ptr<Loud>(new Loud('y')));
    b.push_back(shared_ptr<Loud>(new Loud('z')));
    a = b;
}
cout << "done\n";
Loud::Loud() [c='x']
Loud::Loud() [c='y']
Loud::Loud() [c='z']
done
Loud::~Loud() [c='x']
Loud::~Loud() [c='y']
Loud::~Loud() [c='z']

The a = b assignment only copied (shared) pointers, not the actual Loud objects. We’d have heard, if it did.

vector of shared_ptr example

vector<shared_ptr<Loud>> a;
{
    vector<shared_ptr<Loud>> b;
    b.emplace_back(new Loud('x'));
    b.emplace_back(new Loud('y'));
    b.emplace_back(new Loud('z'));
    a = b;
}
cout << "done\n";
Loud::Loud() [c='x']
Loud::Loud() [c='y']
Loud::Loud() [c='z']
done
Loud::~Loud() [c='x']
Loud::~Loud() [c='y']
Loud::~Loud() [c='z']

vector::emplace_back() builds a shared_ptr in place inside the vector, rather than creating/copying/destroying a temporary shared_ptr.

Did it really do copying in the previous example?

Weak Pointers

Weak Pointers

Weak Pointers

weak_ptr example

weak_ptr<int> wp;

void observe() {
    cout << "use_count=" << wp.use_count() << ": ";
    if (auto sp = wp.lock())
        cout << *sp << '\n';
    else
        cout << "expired\n";
}

int main() {
    {
        shared_ptr<int> mem(new int(42));
        wp = mem;
        observe();
    }

    observe();
}
use_count=1: 42
use_count=0: expired

weak_ptr: why?