std::shared_ptr allows several owners to share one object safely.

shared ownership A `std::shared_ptr` keeps the object alive until the last shared owner is gone.

Shared Ptr

example
shared_ptr.cpp
Replay: real traced execution (multi-file project)
#include <iostream>
#include <memory>

class Counter {
private:
    int value;

public:
    Counter(int start) {
        value = start;
    }

    void add(int amount) {
        value += amount;
    }

    int current() {
        return value;
    }
};

int main() {
    int start = 10;
    int amount = 5;

    std::shared_ptr<Counter> first = std::make_shared<Counter>(start);

    {
        std::shared_ptr<Counter> second = first;
        second->add(amount);
        std::cout << "insideOwners=" << first.use_count() << std::endl;
    }

    std::cout << "outsideOwners=" << first.use_count() << std::endl;
    std::cout << "value=" << first->current() << std::endl;
    return 0;
}
#include <iostream>
#include <memory>

class Counter {
private:
    int value;

public:
    Counter(int start) {
        value = start;
    }

    void add(int amount) {
        value += amount;
    }

    int current() {
        return value;
    }
};

int main() {
    int start = 1;
    int amount = 5;

    std::shared_ptr<Counter> first = std::make_shared<Counter>(start);

    {
        std::shared_ptr<Counter> second = first;
        second->add(amount);
        std::cout << "insideOwners=" << first.use_count() << std::endl;
    }

    std::cout << "outsideOwners=" << first.use_count() << std::endl;
    std::cout << "value=" << first->current() << std::endl;
    return 0;
}
#include <iostream>
#include <memory>

class Counter {
private:
    int value;

public:
    Counter(int start) {
        value = start;
    }

    void add(int amount) {
        value += amount;
    }

    int current() {
        return value;
    }
};

int main() {
    int start = 25;
    int amount = 5;

    std::shared_ptr<Counter> first = std::make_shared<Counter>(start);

    {
        std::shared_ptr<Counter> second = first;
        second->add(amount);
        std::cout << "insideOwners=" << first.use_count() << std::endl;
    }

    std::cout << "outsideOwners=" << first.use_count() << std::endl;
    std::cout << "value=" << first->current() << std::endl;
    return 0;
}
#include <iostream>
#include <memory>

class Counter {
private:
    int value;

public:
    Counter(int start) {
        value = start;
    }

    void add(int amount) {
        value += amount;
    }

    int current() {
        return value;
    }
};

int main() {
    int start = 10;
    int amount = 2;

    std::shared_ptr<Counter> first = std::make_shared<Counter>(start);

    {
        std::shared_ptr<Counter> second = first;
        second->add(amount);
        std::cout << "insideOwners=" << first.use_count() << std::endl;
    }

    std::cout << "outsideOwners=" << first.use_count() << std::endl;
    std::cout << "value=" << first->current() << std::endl;
    return 0;
}
#include <iostream>
#include <memory>

class Counter {
private:
    int value;

public:
    Counter(int start) {
        value = start;
    }

    void add(int amount) {
        value += amount;
    }

    int current() {
        return value;
    }
};

int main() {
    int start = 10;
    int amount = 10;

    std::shared_ptr<Counter> first = std::make_shared<Counter>(start);

    {
        std::shared_ptr<Counter> second = first;
        second->add(amount);
        std::cout << "insideOwners=" << first.use_count() << std::endl;
    }

    std::cout << "outsideOwners=" << first.use_count() << std::endl;
    std::cout << "value=" << first->current() << std::endl;
    return 0;
}
  1. start ← 10, amount ← 5

    22int main() {23    int start→ 10 = 10; //@start=1, 2524    int amount→ 5 = 5; //@amount=2, 102526    std::shared_ptr<Counter> first = std::make_shared<Counter>(start10);
  2. value ← 10

    8public:9    Counter(int start10) {10        value→ 10 = start10;11    }
  3. first ← ⟨addr A⟩, second ← ⟨addr A⟩

    26std::shared_ptr<Counter> first→ ⟨addr A⟩ = std::make_shared<Counter>(start10);2728{29    std::shared_ptr<Counter> second→ ⟨addr A⟩ = first⟨addr A⟩;30    second⟨addr A⟩->add(amount5);31    std::cout << "insideOwners=" << first.use_count() << std::endl;
  4. value ← 15

    13void add(int amount5) {14    value→ 15 += amount5;15}
  5. second->add(amount);

    29    std::shared_ptr<Counter> second = first;30    second⟨addr A⟩->add(amount5);31    std::cout << "insideOwners=" << first⟨addr A⟩.use_count() << std::endl;32}3334std::cout << "outsideOwners=" << first⟨addr A⟩.use_count() << std::endl;35std::cout << "value=" << first⟨addr A⟩->current() << std::endl;36return 0;
    outputinsideOwners=2
    outsideOwners=1
  6. int current()

    17int current() {18    return value15;19}
  7. std::cout << "value=" << first->current() << std::endl;

    34    std::cout << "outsideOwners=" << first.use_count() << std::endl;35    std::cout << "value=" << first⟨addr A⟩->current() << std::endl;36    return 0;37}
    outputvalue=15
  1. start ← 1, amount ← 5

    22int main() {23    int start→ 1 = 1;24    int amount→ 5 = 5;2526    std::shared_ptr<Counter> first = std::make_shared<Counter>(start1);
  2. value ← 1

    8public:9    Counter(int start1) {10        value→ 1 = start1;11    }
  3. first ← ⟨addr A⟩, second ← ⟨addr A⟩

    26std::shared_ptr<Counter> first→ ⟨addr A⟩ = std::make_shared<Counter>(start1);2728{29    std::shared_ptr<Counter> second→ ⟨addr A⟩ = first⟨addr A⟩;30    second⟨addr A⟩->add(amount5);31    std::cout << "insideOwners=" << first.use_count() << std::endl;
  4. value ← 6

    13void add(int amount5) {14    value→ 6 += amount5;15}
  5. second->add(amount);

    29    std::shared_ptr<Counter> second = first;30    second⟨addr A⟩->add(amount5);31    std::cout << "insideOwners=" << first⟨addr A⟩.use_count() << std::endl;32}3334std::cout << "outsideOwners=" << first⟨addr A⟩.use_count() << std::endl;35std::cout << "value=" << first⟨addr A⟩->current() << std::endl;36return 0;
    outputinsideOwners=2
    outsideOwners=1
  6. int current()

    17int current() {18    return value6;19}
  7. std::cout << "value=" << first->current() << std::endl;

    34    std::cout << "outsideOwners=" << first.use_count() << std::endl;35    std::cout << "value=" << first⟨addr A⟩->current() << std::endl;36    return 0;37}
    outputvalue=6
  1. start ← 25, amount ← 5

    22int main() {23    int start→ 25 = 25;24    int amount→ 5 = 5;2526    std::shared_ptr<Counter> first = std::make_shared<Counter>(start25);
  2. value ← 25

    8public:9    Counter(int start25) {10        value→ 25 = start25;11    }
  3. first ← ⟨addr A⟩, second ← ⟨addr A⟩

    26std::shared_ptr<Counter> first→ ⟨addr A⟩ = std::make_shared<Counter>(start25);2728{29    std::shared_ptr<Counter> second→ ⟨addr A⟩ = first⟨addr A⟩;30    second⟨addr A⟩->add(amount5);31    std::cout << "insideOwners=" << first.use_count() << std::endl;
  4. value ← 30

    13void add(int amount5) {14    value→ 30 += amount5;15}
  5. second->add(amount);

    29    std::shared_ptr<Counter> second = first;30    second⟨addr A⟩->add(amount5);31    std::cout << "insideOwners=" << first⟨addr A⟩.use_count() << std::endl;32}3334std::cout << "outsideOwners=" << first⟨addr A⟩.use_count() << std::endl;35std::cout << "value=" << first⟨addr A⟩->current() << std::endl;36return 0;
    outputinsideOwners=2
    outsideOwners=1
  6. int current()

    17int current() {18    return value30;19}
  7. std::cout << "value=" << first->current() << std::endl;

    34    std::cout << "outsideOwners=" << first.use_count() << std::endl;35    std::cout << "value=" << first⟨addr A⟩->current() << std::endl;36    return 0;37}
    outputvalue=30
  1. start ← 10, amount ← 2

    22int main() {23    int start→ 10 = 10;24    int amount→ 2 = 2;2526    std::shared_ptr<Counter> first = std::make_shared<Counter>(start10);
  2. value ← 10

    8public:9    Counter(int start10) {10        value→ 10 = start10;11    }
  3. first ← ⟨addr A⟩, second ← ⟨addr A⟩

    26std::shared_ptr<Counter> first→ ⟨addr A⟩ = std::make_shared<Counter>(start10);2728{29    std::shared_ptr<Counter> second→ ⟨addr A⟩ = first⟨addr A⟩;30    second⟨addr A⟩->add(amount2);31    std::cout << "insideOwners=" << first.use_count() << std::endl;
  4. value ← 12

    13void add(int amount2) {14    value→ 12 += amount2;15}
  5. second->add(amount);

    29    std::shared_ptr<Counter> second = first;30    second⟨addr A⟩->add(amount2);31    std::cout << "insideOwners=" << first⟨addr A⟩.use_count() << std::endl;32}3334std::cout << "outsideOwners=" << first⟨addr A⟩.use_count() << std::endl;35std::cout << "value=" << first⟨addr A⟩->current() << std::endl;36return 0;
    outputinsideOwners=2
    outsideOwners=1
  6. int current()

    17int current() {18    return value12;19}
  7. std::cout << "value=" << first->current() << std::endl;

    34    std::cout << "outsideOwners=" << first.use_count() << std::endl;35    std::cout << "value=" << first⟨addr A⟩->current() << std::endl;36    return 0;37}
    outputvalue=12
  1. start ← 10, amount ← 10

    22int main() {23    int start→ 10 = 10;24    int amount→ 10 = 10;2526    std::shared_ptr<Counter> first = std::make_shared<Counter>(start10);
  2. value ← 10

    8public:9    Counter(int start10) {10        value→ 10 = start10;11    }
  3. first ← ⟨addr A⟩, second ← ⟨addr A⟩

    26std::shared_ptr<Counter> first→ ⟨addr A⟩ = std::make_shared<Counter>(start10);2728{29    std::shared_ptr<Counter> second→ ⟨addr A⟩ = first⟨addr A⟩;30    second⟨addr A⟩->add(amount10);31    std::cout << "insideOwners=" << first.use_count() << std::endl;
  4. value ← 20

    13void add(int amount10) {14    value→ 20 += amount10;15}
  5. second->add(amount);

    29    std::shared_ptr<Counter> second = first;30    second⟨addr A⟩->add(amount10);31    std::cout << "insideOwners=" << first⟨addr A⟩.use_count() << std::endl;32}3334std::cout << "outsideOwners=" << first⟨addr A⟩.use_count() << std::endl;35std::cout << "value=" << first⟨addr A⟩->current() << std::endl;36return 0;
    outputinsideOwners=2
    outsideOwners=1
  6. int current()

    17int current() {18    return value20;19}
  7. std::cout << "value=" << first->current() << std::endl;

    34    std::cout << "outsideOwners=" << first.use_count() << std::endl;35    std::cout << "value=" << first⟨addr A⟩->current() << std::endl;36    return 0;37}
    outputvalue=20

Count the Owners

  1. first owns the Counter.
  2. Inside the block, second = first shares the same object.
  3. second->add(amount) changes the shared counter.
  4. Leaving the block destroys second.
  5. first remains and still sees the updated value. | Moment | Owner count | Counter value | | --- | --- | --- | | inside block | 2 | 15 | | outside block | 1 | 15 |

Exercise: shared_ptr.cpp

Share one Counter inside a nested block, print owner counts, and keep the updated value afterward