Назад к вопросам
Middle
84
questionbank

Как осуществляется подсчет ссылок в shared_ptr?

Sobes Copilot

Получайте ответы в реальном времени

Ответ от нейросети

sobes.tech AI

shared_ptr использует внутренний управляющий блок (control block), который содержит счетчик сильных ссылок (strong count) и счетчик слабых ссылок (weak count).

Механизм работы:

  1. Создание: При создании первого shared_ptr, указывающего на объект, создается управляющий блок с обоими счетчиками, инициализированными в 1.
    #include <memory>
    
    int main() {
        auto ptr = std::make_shared<int>(10); // Создается control block, strong_count = 1, weak_count = 1 (указатель в control block тоже считается)
        return 0;
    }
    
  2. Копирование shared_ptr: При копировании shared_ptr увеличивается strong_count в том же управляющем блоке.
    #include <memory>
    
    int main() {
        auto ptr1 = std::make_shared<int>(10); // strong_count = 1
        auto ptr2 = ptr1;                     // strong_count увеличивается до 2
        return 0;
    }
    
  3. Присваивание shared_ptr: Присваивание одного shared_ptr другому уменьшает strong_count у левого операнда (если он указывал на объект) и увеличивает strong_count у правого операнда.
  4. Создание weak_ptr: При создании weak_ptr из shared_ptr увеличивается weak_count в том же управляющем блоке. strong_count при этом не меняется.
    #include <memory>
    #include <weak_ptr>
    
    int main() {
        auto ptr = std::make_shared<int>(10); // strong_count = 1, weak_count = 1
        std::weak_ptr<int> weak_ptr = ptr;   // weak_count увеличивается до 2
        return 0;
    }
    
  5. Выход из области видимости или сброс: При уничтожении shared_ptr (например, при выходе из области видимости или вызове reset()) уменьшается strong_count.
    #include <memory>
    
    int main() {
        {
            auto ptr = std::make_shared<int>(10); // strong_count = 1
        } // strong_count уменьшается до 0
        return 0;
    }
    
    #include <memory>
    
    int main() {
        auto ptr = std::make_shared<int>(10); // strong_count = 1
        ptr.reset();                          // strong_count уменьшается до 0
        return 0;
    }
    
  6. Освобождение объекта: Когда strong_count становится равным 0, объект, на который указывал shared_ptr, удаляется.
  7. Освобождение управляющего блока: Когда и strong_count, и weak_count равны 0, управляющий блок удаляется.
  8. Выход из области видимости или сброс weak_ptr: При уничтожении weak_ptr уменьшается weak_count.
    #include <memory>
    #include <weak_ptr>
    
    int main() {
        auto ptr = std::make_shared<int>(10); // strong_count = 1, weak_count = 1
        {
            std::weak_ptr<int> weak_ptr = ptr; // weak_count = 2
        } // weak_count уменьшается до 1
        return 0;
    }
    

Подсчет ссылок является потокобезопасным благодаря атомарным операциям над счетчиками внутри управляющего блока.

Пример структуры управляющего блока (упрощенно):

struct ControlBlock {
    std::atomic<long> strong_count{1};
    std::atomic<long> weak_count{1}; // Изначально 1, так как control block хранит свой указатель
    // Дополнительная информация, такая как deleter, allocator
};