Middle
Kaip veikia nuorodų skaitiklis std::shared_ptr?
sobes.tech AI
Atsakymas iš AI
std::shared_ptr nuorodų skaitiklis saugomas atskirame objekte — valdymo bloke (control block).
Šis valdymo blokas sukuriamas:
- Kai pirmą kartą sukuriamas
std::shared_ptriš rodyklės. - Kai sukuriamas
std::shared_ptrsu naudotojo nurodytu ištrynėju ar alokatoriumi. - Kai naudojama
std::make_sharedarbastd::allocate_shared.
Šis valdymo blokas turi bent du skaitiklius:
- Stiprių nuorodų skaitiklis (strong count): Didėja kuriant arba kopijuojant
std::shared_ptr. Mažėja naikinantstd::shared_ptr. Kai šis skaitiklis pasiekia nulį, valdomas objektas išlaisvinamas. - Silpnų nuorodų skaitiklis (weak count): Didėja kuriant
std::weak_ptrišstd::shared_ptr. Mažėja naikinantstd::weak_ptr. Valdymo blokas išlaisvinamas, kai abu skaitikliai — stiprus ir silpnas — pasiekia nulį.
std::make_shared naudojimas yra pageidautinas prieš tiesioginį new naudojimą, nes jis gali alokuoti objektą ir valdymo bloką viename atminties bloke, tai pagerina našumą ir sumažina fragmentaciją.
Atominiai skaitikliai užtikrina std::shared_ptr saugumą daugiagijų scenarijuose, nors prieiga prie valdomo objekto pagal numatytuosius nustatymus nėra sinchronizuota.
Pavyzdys:
#include <iostream>
#include <memory>
struct MyObject {
int data;
MyObject(int d) : data(d) {
std::cout << "MyObject(" << data << ") sukurtas\n";
}
~MyObject() {
std::cout << "MyObject(" << data << ") sunaikintas\n";
}
};
int main() {
std::shared_ptr<MyObject> ptr1 = std::make_shared<MyObject>(10);
// stiprus skaitiklis: 1, silpnas skaitiklis: 0
{
std::shared_ptr<MyObject> ptr2 = ptr1;
// stiprus skaitiklis: 2, silpnas skaitiklis: 0
std::weak_ptr<MyObject> weak_ptr = ptr1;
// stiprus skaitiklis: 2, silpnas skaitiklis: 1
if (auto locked_ptr = weak_ptr.lock()) {
// stiprus skaitiklis: 3, silpnas skaitiklis: 1 (lock metu)
std::cout << "Objekto duomenys: " << locked_ptr->data << std::endl;
}
// stiprus skaitiklis: 2, silpnas skaitiklis: 1
} // ptr2 išeina iš apimties
// stiprus skaitiklis: 1, silpnas skaitiklis: 1
// Objekto dar nėra sunaikintas, nes stiprus skaitiklis == 1
{
std::weak_ptr<MyObject> weak_ptr2 = ptr1;
// stiprus skaitiklis: 1, silpnas skaitiklis: 2
} // weak_ptr2 išeina iš apimties
// stiprus skaitiklis: 1, silpnas skaitiklis: 1
} // ptr1 išeina iš apimties
// stiprus skaitiklis: 0, silpnas skaitiklis: 1
// Objekto sunaikinimas, nes stiprus skaitiklis tapo 0
// Valdymo blokas lieka tol, kol silpnas skaitiklis nepasiekia 0