Sobes.tech
Middle+

How does the counter work in shared_ptr?

sobes.tech AI

Answer from AI

std::shared_ptr uses two counters:

  1. Use count: An atomic counter that is incremented when a new shared_ptr copy is made pointing to the same object, and decremented when a shared_ptr is destroyed. When it reaches zero, the object pointed to by shared_ptr is deleted.
  2. Weak count: An atomic counter that is incremented when a std::weak_ptr is created from this shared_ptr and decremented when the weak_ptr is destroyed. When it reaches zero, the control block containing both counters is deleted.

These counters are stored in a separate control block, which is dynamically allocated when the first shared_ptr for the object is created. The control block can also contain a deleter and allocator for the object.

Using atomic counters ensures thread safety when copying and destroying shared_ptrs from different threads. However, access to the object pointed to by shared_ptr is not thread-safe unless the object itself is inherently thread-safe.

// Example demonstrating counter management
struct MyObject {
    int data;
    MyObject(int d) : data(d) { /* ... */ }
    ~MyObject() { /* ... */ } // Destructor called when use_count == 0
};

int main() {
    std::shared_ptr<MyObject> sp1 = std::make_shared<MyObject>(10);
    // use_count == 1, weak_count == 0

    std::shared_ptr<MyObject> sp2 = sp1;
    // use_count == 2, weak_count == 0

    std::weak_ptr<MyObject> wp1 = sp1;
    // use_count == 2, weak_count == 1

    sp1.reset();
    // use_count == 1, weak_count == 1 (object still alive)

    {
        std::shared_ptr<MyObject> sp3 = wp1.lock();
        // Object still exists, sp3 created
        // use_count == 2, weak_count == 1
    } // sp3 goes out of scope
    // use_count == 1, weak_count == 1

    sp2.reset();
    // use_count == 0, weak_count == 1 (object deleted!)

    wp1.reset(); // weak_ptr destroyed
    // use_count == 0, weak_count == 0 (control block deleted)

    return 0;
}