Middle
Hogyan működik a hivatkozásszámláló a std::shared_ptr-ben?
sobes.tech MI
Válasz az MI-től
A std::shared_ptr hivatkozásszámlálója egy külön objektumban, az ellenőrző blokkban (control block) tárolódik.
Ez az ellenőrző blokk akkor jön létre:
- Amikor először hozunk létre
std::shared_ptr-t mutatóval. - Amikor
std::shared_ptr-t hozunk létre egyedi törlővel vagy allokátorral. - A
std::make_sharedvagystd::allocate_sharedhasználatakor.
Ez az ellenőrző blokk legalább két számlálót tartalmaz:
- Erős hivatkozásszámláló (strong count): Növekszik, amikor
std::shared_ptr-t hozunk létre vagy másolunk. Csökken, amikorstd::shared_ptr-t törlünk. Ha ez a számláló nullára csökken, az irányított objektum felszabadul. - Gyenge hivatkozásszámláló (weak count): Növekszik, amikor
std::weak_ptr-t hozunk létrestd::shared_ptr-ból. Csökken, amikorstd::weak_ptr-t törlünk. Az ellenőrző blokk akkor szabadul fel, amikor mindkét számláló — erős és gyenge — nullára csökken.
A std::make_shared használata előnyösebb, mint a közvetlen new-elés, mert az objektumot és az ellenőrző blokkot egyetlen memória blokkban tudja lefoglalni, ez javítja a teljesítményt és csökkenti a fragmentációt.
A számlálók atomikusak, így a std::shared_ptr biztonságos több szálon való használatra, bár az irányított objektumhoz való hozzáférés alapértelmezés szerint nem szinkronizált.
Példa:
#include <iostream>
#include <memory>
struct MyObject {
int data;
MyObject(int d) : data(d) {
std::cout << "MyObject(" << data << ") létrehozva\n";
}
~MyObject() {
std::cout << "MyObject(" << data << ") megsemmisítve\n";
}
};
int main() {
std::shared_ptr<MyObject> ptr1 = std::make_shared<MyObject>(10);
// erős számláló: 1, gyenge számláló: 0
{
std::shared_ptr<MyObject> ptr2 = ptr1;
// erős számláló: 2, gyenge számláló: 0
std::weak_ptr<MyObject> weak_ptr = ptr1;
// erős számláló: 2, gyenge számláló: 1
if (auto locked_ptr = weak_ptr.lock()) {
// erős számláló: 3, gyenge számláló: 1 (ideiglenes lock alatt)
std::cout << "Objektum adatai: " << locked_ptr->data << std::endl;
}
// erős számláló: 2, gyenge számláló: 1
} // ptr2 kilép a scope-ból
// erős számláló: 1, gyenge számláló: 1
// Az objektum még nem lett megsemmisítve, mert az erős számláló == 1
{
std::weak_ptr<MyObject> weak_ptr2 = ptr1;
// erős számláló: 1, gyenge számláló: 2
} // weak_ptr2 kilép a scope-ból
// erős számláló: 1, gyenge számláló: 1
} // ptr1 kilép a scope-ból
// erős számláló: 0, gyenge számláló: 1
// Az objektum megsemmisül, mert az erős számláló elérte a 0-t
// Az ellenőrző blokk akkor szabadul fel, amikor a gyenge számláló is 0 lesz