Назад к вопросам
Middle+
92
questionbank
Как работает счетчик в shared_ptr?
Sobes Copilot
Получайте ответы в реальном времени
Ответ от нейросети
sobes.tech AI
В std::shared_ptr используется два счетчика:
- Use count (Счетчик ссылок): Атомарный счетчик, который инкрементируется при создании новой копии
shared_ptr, указывающей на тот же объект, и декрементируется при разрушенииshared_ptr. Когда достигает нуля, объект, на который указываетshared_ptr, удаляется. - Weak count (Счетчик слабых ссылок): Атомарный счетчик, который инкрементируется при создании
std::weak_ptrиз данногоshared_ptrи декрементируется при разрушенииweak_ptr. Когда достигает нуля, блок управления (control block), содержащий оба счетчика, удаляется.
Эти счетчики хранятся в отдельном блоке управления (control block), который выделяется динамически при первом создании shared_ptr для объекта. Control block также может содержать deleter и allocator для объекта.
Использование атомарных счетчиков обеспечивает потокобезопасность при копировании и разрушении shared_ptr из разных потоков. Однако сам доступ к объекту, на который указывает shared_ptr, не потокобезопасен, если объект не является таковым изначально.
// Пример демонстрирующий управление счетчиками
struct MyObject {
int data;
MyObject(int d) : data(d) { /* ... */ }
~MyObject() { /* ... */ } // Деструктор вызывается при 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 (объект еще жив)
{
std::shared_ptr<MyObject> sp3 = wp1.lock();
// Объект все еще существует, sp3 создан
// use_count == 2, weak_count == 1
} // sp3 выходит из области видимости
// use_count == 1, weak_count == 1
sp2.reset();
// use_count == 0, weak_count == 1 (объект удален!)
wp1.reset(); // weak_ptr разрушен
// use_count == 0, weak_count == 0 (control block удален)
return 0;
}