CS253: Software Development with C++

Fall 2019

Smart Pointers

Show Lecture.SmartPointers as a slide show.

CS253 Smart Pointers

Overview

The Problem

#include "Loud.h"
int main(int argc, char **) {
    auto p = new Loud;
    if (argc < 5) {
        cerr << "Not enough arguments.\n";
        return 1;
    }
    delete p;
    return 0;
}
Loud::Loud()
Not enough arguments.

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

#include "Loud.h"

int main(int argc, char **) {
    unique_ptr<Loud> p(new Loud);
    if (argc < 5) {
        cerr << "Not enough arguments.\n";
        return 1;
    }
    // don’t need to delete
    return 0;
}
Loud::Loud()
Not enough arguments.
Loud::~Loud()

unique_ptr example #2

#include "Loud.h"

void foo() {
    unique_ptr<Loud> p(new Loud);
    throw logic_error("boo hoo");
}

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

shared_ptr

shared_ptr example

#include "Loud.h"
int main() {
    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

#include "Loud.h"
int main() {
    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

#include "Loud.h"
int main() {
    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(cpp)»() 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

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

weak_ptr<int> wp;

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

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

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

weak_ptr: why?