Middle
Cum funcționează contorul de referințe în std::shared_ptr?
sobes.tech AI
Răspuns de la AI
Contorul de referințe din std::shared_ptr este stocat într-un obiect separat: în blocul de control (control block).
Acest bloc de control este creat:
- La prima creare a unui
std::shared_ptrdintr-un pointer. - La crearea unui
std::shared_ptrcu un deleter sau allocator personalizat. - La utilizarea
std::make_sharedsaustd::allocate_shared.
Acest bloc de control conține cel puțin doi contori:
- Contorul de referințe puternice (strong count): Se mărește la crearea sau copierea unui
std::shared_ptr. Se scade la distrugerea unuistd::shared_ptr. Când acest contor ajunge la zero, obiectul gestionat este eliberat. - Contorul de referințe slabe (weak count): Se mărește la crearea unui
std::weak_ptrdintr-unstd::shared_ptr. Se scade la distrugerea unuistd::weak_ptr. Blocul de control este eliberat când ambele contoare — puternic și slab — ajung la zero.
Utilizarea std::make_shared este preferabilă față de crearea directă cu new, deoarece poate aloca obiectul și blocul de control într-un singur bloc de memorie, ceea ce îmbunătățește performanța și reduce fragmentarea.
Contorii sunt atomici, ceea ce face ca std::shared_ptr să fie sigur pentru utilizarea în scenarii multithread, deși accesul la obiectul gestionat nu este sincronizat implicit.
Exemplu:
#include <iostream>
#include <memory>
struct MyObject {
int data;
MyObject(int d) : data(d) {
std::cout << "MyObject(" << data << ") creat\n";
}
~MyObject() {
std::cout << "MyObject(" << data << ") distrus\n";
}
};
int main() {
std::shared_ptr<MyObject> ptr1 = std::make_shared<MyObject>(10);
// contor puternic: 1, contor slab: 0
{
std::shared_ptr<MyObject> ptr2 = ptr1;
// contor puternic: 2, contor slab: 0
std::weak_ptr<MyObject> weak_ptr = ptr1;
// contor puternic: 2, contor slab: 1
if (auto locked_ptr = weak_ptr.lock()) {
// contor puternic: 3, contor slab: 1 (temporar în lock)
std::cout << "Date obiect: " << locked_ptr->data << std::endl;
}
// contor puternic: 2, contor slab: 1
} // ptr2 iese din scope
// contor puternic: 1, contor slab: 1
// Obiectul nu a fost încă distrus, deoarece contorul puternic == 1
{
std::weak_ptr<MyObject> weak_ptr2 = ptr1;
// contor puternic: 1, contor slab: 2
} // weak_ptr2 iese din scope
// contor puternic: 1, contor slab: 1
} // ptr1 iese din scope
// contor puternic: 0, contor slab: 1
// Obiectul este distrus, deoarece contorul puternic a ajuns la 0
// Blocul de control rămâne până când contorul slab ajunge la 0