Middle
Как работи броячът на препратки в std::shared_ptr?
sobes.tech AI
Отговор от AI
Броячът за връзки в std::shared_ptr се съхранява в отделен обект — блок за управление (control block).
Блокът за управление се създава:
- При първото създаване на
std::shared_ptrот указател. - При създаване на
std::shared_ptrс потребителски изтривател или алокатор. - При използване на
std::make_sharedилиstd::allocate_shared.
Този блок за управление съдържа поне два брояча:
- Брояч на силните връзки (strong count): Увеличава се при създаване или копиране на
std::shared_ptr. Намалява се при унищожаване наstd::shared_ptr. Когато този брояч стане нула, се освобождава управляваният обект. - Брояч на слабите връзки (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);
// силен брояч: 1, слаб брояч: 0
{
std::shared_ptr<MyObject> ptr2 = ptr1;
// силен брояч: 2, слаб брояч: 0
std::weak_ptr<MyObject> weak_ptr = ptr1;
// силен брояч: 2, слаб брояч: 1
if (auto locked_ptr = weak_ptr.lock()) {
// силен брояч: 3, слаб брояч: 1 (вътре в lock)
std::cout << "Object data: " << locked_ptr->data << std::endl;
}
// силен брояч: 2, слаб брояч: 1
} // ptr2 излиза извън обхвата си
// силен брояч: 1, слаб брояч: 1
// Обектът все още не е унищожен, тъй като силният брояч == 1
{
std::weak_ptr<MyObject> weak_ptr2 = ptr1;
// силен брояч: 1, слаб брояч: 2
} // weak_ptr2 излиза извън обхвата си
// силен брояч: 1, слаб брояч: 1
} // ptr1 излиза извън обхвата си
// силен брояч: 0, слаб брояч: 1
// Обектът се унищожава, тъй като силният брояч става 0
// Блокът за управление остава, докато слабият брояч не стане 0