C/C++ Arena

Step 4 of 5

shared_ptr

Sometimes there really isn't one owner. Several parts of a program need the same object, and it should live until the last of them is done with it. For that there's std::shared_ptr<T>.

A shared_ptr keeps a reference count next to the object: how many shared_ptrs currently own it. Copying a shared_ptr adds one, destroying one subtracts one, and when the count reaches zero the object is deleted. use_count() shows the current count.

#include <iostream>
#include <memory>
#include <string>
#include <vector>

struct Texture {
    std::string file;
    ~Texture() { std::cout << "unload " << file << "\n"; }
};

int main() {
    std::vector<std::shared_ptr<Texture>> sprites;
    {
        auto grass = std::make_shared<Texture>(Texture{"grass.png"});
        std::cout << "count " << grass.use_count() << "\n";
        sprites.push_back(grass);
        sprites.push_back(grass);
        std::cout << "count " << grass.use_count() << "\n";
    }
    std::cout << "block done, count " << sprites[0].use_count() << "\n";
    sprites.clear();
    std::cout << "end of main\n";
}
unload grass.png
count 1
count 3
block done, count 2
unload grass.png
end of main

Reading the output

When to use which

Prefer unique_ptr. It's simpler and faster. shared_ptr needs a separate control block for the count (make_shared puts it in the same allocation as the object, which is one reason to prefer it) and an atomic update on every copy. Reach for it only when ownership is genuinely shared and there's no single obvious owner.

Your turn: make the program print 1 2 3 2 by filling in the blanks.

Previous: Returning ownership Next: weak_ptr