Sobes.tech
Middle

Kā darbojas atsauces skaitītājs std::shared_ptr?

sobes.tech AI

Atbilde no AI

std::shared_ptr saites skaitītājs tiek glabāts atsevišķā objektā — kontroles blokā (control block).

Šis kontroles bloks tiek izveidots:

  • Pirmo reizi, kad std::shared_ptr tiek izveidots no norādītāja.
  • Izveidojot std::shared_ptr ar lietotāja definētu dzēšēju vai alokatoru.
  • Izmantojot std::make_shared vai std::allocate_shared.

Šis kontroles bloks satur vismaz divus skaitītājus:

  1. Stipro saišu skaitītājs (strong count): Palielinās, veidojot vai kopējot std::shared_ptr. Samazinās, to iznīcinot. Kad šis skaitītājs sasniedz nulli, pārvaldītais objekts tiek atbrīvots.
  2. Vāju saišu skaitītājs (weak count): Palielinās, veidojot std::weak_ptr no std::shared_ptr. Samazinās, to iznīcinot. Kontroles bloks tiek atbrīvots, kad abi skaitītāji — stiprais un vājš — sasniedz nulli.

std::make_shared ir vēlams izmantot, nevis tieši new lietot, jo tas var alocēt objektu un kontroles bloku vienā atmiņas blokā, uzlabojot veiktspēju un samazinot fragmentāciju.

Akmati skaitītāji nodrošina std::shared_ptr drošību daudzprocesu scenārijos, lai gan piekļuve pārvaldītajam objektam pēc noklusējuma nav sinhronizēta.

Piemērs:

#include <iostream>
#include <memory>

struct MyObject {
    int data;
    MyObject(int d) : data(d) {
        std::cout << "MyObject(" << data << ") izveidots\n";
    }
    ~MyObject() {
        std::cout << "MyObject(" << data << ") iznīcināts\n";
    }
};

int main() {
    std::shared_ptr<MyObject> ptr1 = std::make_shared<MyObject>(10);
    // stiprais skaitītājs: 1, vājš skaitītājs: 0

    {
        std::shared_ptr<MyObject> ptr2 = ptr1;
        // stiprais skaitītājs: 2, vājš skaitītājs: 0

        std::weak_ptr<MyObject> weak_ptr = ptr1;
        // stiprais skaitītājs: 2, vājš skaitītājs: 1

        if (auto locked_ptr = weak_ptr.lock()) {
            // stiprais skaitītājs: 3, vājš skaitītājs: 1 (lock laikā)
            std::cout << "Objekta dati: " << locked_ptr->data << std::endl;
        }
        // stiprais skaitītājs: 2, vājš skaitītājs: 1
    } // ptr2 iziet no apjoma
    // stiprais skaitītājs: 1, vājš skaitītājs: 1

    // Objekts vēl nav iznīcināts, jo stiprais skaitītājs == 1

    {
        std::weak_ptr<MyObject> weak_ptr2 = ptr1;
        // stiprais skaitītājs: 1, vājš skaitītājs: 2
    } // weak_ptr2 iziet no apjoma
    // stiprais skaitītājs: 1, vājš skaitītājs: 1

} // ptr1 iziet no apjoma
// stiprais skaitītājs: 0, vājš skaitītājs: 1
// Objekts tiek iznīcināts, jo stiprais skaitītājs kļuva par 0
// Kontroles bloks paliek līdz brīdim, kad vājš skaitītājs kļūst par 0