std::shared_ptr and weak_ptr
An object owned by a std::unique_ptr always has one owner. But sometimes several parts of a program use an object, and nobody knows in advance which one finishes last. That is what std::shared_ptr is for: it can be copied, and all the copies own one object.
#include <iostream>
#include <memory>
int main() {
std::shared_ptr<int> a = std::make_shared<int>(7);
std::shared_ptr<int> b = a;
*b = 8;
std::cout << *a << ' ' << a.use_count() << '\n'; // 8 2
b = nullptr;
std::cout << a.use_count() << '\n'; // 1
}std::make_shared<int>(7) creates the number on the heap together with its first owner. The line std::shared_ptr<int> b = a; copies ownership, not the number. a and b point to the same number, so after *b = 8, the value of *a is 8 too.
Counting owners
This is shared ownership: the object belongs to all the copies at once. A shared_ptr counts the owners, and use_count() returns their number. Each copy adds one to the count. When an owner is destroyed or assigned nullptr, the count goes down.
The object is deleted when the count reaches zero, that is, together with its last owner. Counting costs time and memory, so shared_ptr is used only when there really are several owners. Otherwise, std::unique_ptr is enough.
Weak pointer
std::weak_ptr is a weak pointer: it watches an object owned by shared_ptrs but does not own it. It is created from a shared_ptr, and use_count() does not grow because of it. The lock() method returns a shared_ptr to the object, or an empty shared_ptr if the object is already deleted:
std::shared_ptr<int> owner = std::make_shared<int>(5);
std::weak_ptr<int> watcher = owner;
std::cout << owner.use_count() << '\n'; // 1
owner = nullptr;
std::cout << (watcher.lock() == nullptr) << '\n'; // 1Common mistake
Two objects own each other through shared_ptr:
#include <iostream>
#include <memory>
struct Node {
std::shared_ptr<Node> next;
~Node() { std::cout << "~Node\n"; }
};
int main() {
std::shared_ptr<Node> a = std::make_shared<Node>();
std::shared_ptr<Node> b = std::make_shared<Node>();
a->next = b;
b->next = a; // ✗
}The arrow works with smart pointers too. The program prints nothing. At the end of main, a and b are destroyed, but each Node still owns its neighbor. Both counts stay at one, so the destructors never run and both objects leak.
A weak pointer breaks such a cycle. Declared as std::weak_ptr<Node> next;, the field does not own its neighbor, both counts reach zero, and the program prints ~Node twice. Real programs usually make one link of the two weak—for example, the one from a child object to its parent.