Sobes.tech
Middle

Ako funguje čítač odkazov v std::shared_ptr?

sobes.tech AI

Odpoveď od AI

Počítadlo odkazov v std::shared_ptr sa uchováva v samostatnom objekte — riadiacom bloku.

Riadiaci blok sa vytvára:

  • Pri prvom vytvorení std::shared_ptr z ukazovateľa.
  • Pri vytvorení std::shared_ptr s používateľským vymazávačom alebo alokátorom.
  • Pri použití std::make_shared alebo std::allocate_shared.

Tento riadiaci blok obsahuje aspoň dva počítadlá:

  1. Počítadlo silných odkazov (strong count): Zvyšuje sa pri vytvorení alebo kopírovaní std::shared_ptr. Znižuje sa pri zničení std::shared_ptr. Keď toto počítadlo dosiahne nulu, uvoľní sa riadený objekt.
  2. Počítadlo slabých odkazov (weak count): Zvyšuje sa pri vytvorení std::weak_ptr z std::shared_ptr. Znižuje sa pri zničení std::weak_ptr. Riadiaci blok sa uvoľní, keď obe počítadlá — silné a slabé — dosiahnu nulu.

Použitie std::make_shared je preferované pred priamym vytvorením s new, pretože môže alokovať objekt a riadiaci blok v jednom bloku pamäte, čo zlepšuje výkon a znižuje fragmentáciu.

Atomové počítadlá robia std::shared_ptr bezpečným pre použitie v viacvláknových scenároch, hoci prístup k riadenému objektu nie je predvolený synchronizovaný.

Príklad:

#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);
    // silné počítadlo: 1, slabé počítadlo: 0

    {
        std::shared_ptr<MyObject> ptr2 = ptr1;
        // silné počítadlo: 2, slabé počítadlo: 0

        std::weak_ptr<MyObject> weak_ptr = ptr1;
        // silné počítadlo: 2, slabé počítadlo: 1

        if (auto locked_ptr = weak_ptr.lock()) {
            // silné počítadlo: 3, slabé počítadlo: 1 (vo vnútri lock)
            std::cout << "Object data: " << locked_ptr->data << std::endl;
        }
        // silné počítadlo: 2, slabé počítadlo: 1
    } // ptr2 odchádza z rozsahu
    // silné počítadlo: 1, slabé počítadlo: 1

    // Objekt ešte nebol zničený, pretože silné počítadlo == 1

    {
        std::weak_ptr<MyObject> weak_ptr2 = ptr1;
        // silné počítadlo: 1, slabé počítadlo: 2
    } // weak_ptr2 odchádza z rozsahu
    // silné počítadlo: 1, slabé počítadlo: 1

} // ptr1 odchádza z rozsahu
// silné počítadlo: 0, slabé počítadlo: 1
// Objekt je zničený, pretože silné počítadlo dosiahlo 0
// Riadiaci blok zostáva, kým sa slabé počítadlo nezníži na 0