Sobes.tech
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_ptr iš rodyklės.
  • Kai sukuriamas std::shared_ptr su naudotojo nurodytu ištrynėju ar alokatoriumi.
  • Kai naudojama std::make_shared arba std::allocate_shared.

Šis valdymo blokas turi bent du skaitiklius:

  1. Stiprių nuorodų skaitiklis (strong count): Didėja kuriant arba kopijuojant std::shared_ptr. Mažėja naikinant std::shared_ptr. Kai šis skaitiklis pasiekia nulį, valdomas objektas išlaisvinamas.
  2. Silpnų nuorodų skaitiklis (weak count): Didėja kuriant std::weak_ptrstd::shared_ptr. Mažėja naikinant std::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