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
- The first
unloadline is the temporaryTexture{"grass.png"}passed tomake_shared. It's copied into the shared object and then destroyed. The real texture is only unloaded later. - The count goes 1, then 3 after two copies into the vector.
- When the block ends, the local
grassis gone, but the vector still holds two owners, so the texture stays loaded. sprites.clear()destroys the last two owners, the count hits zero, and the texture is unloaded.
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.