Middle
Hoe werkt de referentieteller in std::shared_ptr?
sobes.tech AI
Antwoord van AI
De referentieteller in std::shared_ptr wordt opgeslagen in een apart object: de control block.
Het control block wordt aangemaakt:
- Bij de eerste creatie van een
std::shared_ptruit een pointer. - Bij het maken van een
std::shared_ptrmet een aangepaste deleter of allocator. - Bij gebruik van
std::make_sharedofstd::allocate_shared.
Dit control block bevat ten minste twee tellers:
- Sterke referentieteller (strong count): Wordt verhoogd bij het maken of kopiëren van een
std::shared_ptr. Wordt verlaagd bij het vernietigen van eenstd::shared_ptr. Wanneer deze teller nul bereikt, wordt het beheerde object vrijgegeven. - Zwakke referentieteller (weak count): Wordt verhoogd bij het maken van een
std::weak_ptruit eenstd::shared_ptr. Wordt verlaagd bij het vernietigen van eenstd::weak_ptr. Het control block wordt vrijgegeven wanneer beide tellers — sterk en zwak — nul worden.
Het gebruik van std::make_shared heeft de voorkeur boven directe creatie met new, omdat het het object en het control block in één geheugenblok kan alloceren, wat de prestaties verbetert en fragmentatie vermindert.
De tellers zijn atomair, wat std::shared_ptr veilig maakt voor gebruik in multithread scenario's, hoewel toegang tot het beheerde object standaard niet gesynchroniseerd is.
Voorbeeld:
#include <iostream>
#include <memory>
struct MyObject {
int data;
MyObject(int d) : data(d) {
std::cout << "MyObject(" << data << ") gemaakt\n";
}
~MyObject() {
std::cout << "MyObject(" << data << ") vernietigd\n";
}
};
int main() {
std::shared_ptr<MyObject> ptr1 = std::make_shared<MyObject>(10);
// sterke teller: 1, zwakke teller: 0
{
std::shared_ptr<MyObject> ptr2 = ptr1;
// sterke teller: 2, zwakke teller: 0
std::weak_ptr<MyObject> weak_ptr = ptr1;
// sterke teller: 2, zwakke teller: 1
if (auto locked_ptr = weak_ptr.lock()) {
// sterke teller: 3, zwakke teller: 1 (tijdelijk in lock)
std::cout << "Object data: " << locked_ptr->data << std::endl;
}
// sterke teller: 2, zwakke teller: 1
} // ptr2 gaat uit scope
// sterke teller: 1, zwakke teller: 1
// Het object is nog niet vernietigd, omdat sterke teller == 1
{
std::weak_ptr<MyObject> weak_ptr2 = ptr1;
// sterke teller: 1, zwakke teller: 2
} // weak_ptr2 gaat uit scope
// sterke teller: 1, zwakke teller: 1
} // ptr1 gaat uit scope
// sterke teller: 0, zwakke teller: 1
// Het object wordt vernietigd, omdat sterke teller 0 is
// Het control block blijft totdat zwakke teller 0 wordt