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

Как работает счетчик ссылок в std::shared_ptr?

Sobes Copilot

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

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

sobes.tech AI

Счетчик ссылок в std::shared_ptr хранится в отдельном объекте — блоке управления (control block).

Блок управления создается:

  • При первом создании std::shared_ptr из указателя.
  • При создании std::shared_ptr с пользовательским удалителем или аллокатором.
  • При использовании std::make_shared или std::allocate_shared.

Этот блок управления содержит как минимум два счетчика:

  1. Счетчик сильных ссылок (strong count): Увеличивается при создании или копировании std::shared_ptr. Уменьшается при уничтожении std::shared_ptr. Когда этот счетчик становится нулем, освобождается управляемый объект.
  2. Счетчик слабых ссылок (weak count): Увеличивается при создании std::weak_ptr из std::shared_ptr. Уменьшается при уничтожении std::weak_ptr. Блок управления освобождается, когда оба счетчика — сильных и слабых ссылок — становятся нулем.

Использование std::make_shared предпочтительнее прямого создания из new, так как оно может аллоцировать объект и блок управления одним блоком памяти, что улучшает производительность и уменьшает фрагментацию.

Счетчики атомарны, что делает std::shared_ptr безопасным для использования в многопоточных сценариях, хотя доступ к самому управляемому объекту не синхронизирован по умолчанию.

Пример:

#include <iostream>
#include <memory>

struct MyObject {
    int data;
    MyObject(int d) : data(d) {
        std::cout << "MyObject(" << data << ") created\n";
    }
    ~MyObject() {
        std::cout << "MyObject(" << data << ") destroyed\n";
    }
};

int main() {
    std::shared_ptr<MyObject> ptr1 = std::make_shared<MyObject>(10);
    // strong count: 1, weak count: 0

    {
        std::shared_ptr<MyObject> ptr2 = ptr1;
        // strong count: 2, weak count: 0

        std::weak_ptr<MyObject> weak_ptr = ptr1;
        // strong count: 2, weak count: 1

        if (auto locked_ptr = weak_ptr.lock()) {
            // strong count: 3, weak count: 1 (внутри lock, временно)
            std::cout << "Object data: " << locked_ptr->data << std::endl;
        }
        // strong count: 2, weak count: 1
    } // ptr2 выходит из области видимости
    // strong count: 1, weak count: 1

    // Объект еще не уничтожен, так как strong count == 1

    {
        std::weak_ptr<MyObject> weak_ptr2 = ptr1;
        // strong count: 1, weak count: 2
    } // weak_ptr2 выходит из области видимости
    // strong count: 1, weak count: 1

} // ptr1 выходит из области видимости
// strong count: 0, weak count: 1
// Объект уничтожается, так как strong count стал 0
// Блок управления остается до тех пор, пока weak count не станет 0