Sobes.tech
Middle

Kuidas töötab std::shared_ptr viidete loendur?

sobes.tech AI

Vastus AI-lt

std::shared_ptr viitearv loetakse eraldi objektis — juhtimisblokis (control block).

See juhtimisblokk luuakse:

  • Esimese std::shared_ptr loomisel viitest.
  • Kasutaja määratud kustutaja või allocatoriga std::shared_ptr loomisel.
  • Kasutades std::make_shared või std::allocate_shared.

See juhtimisblokk sisaldab vähemalt kahte loendurit:

  1. Tugevate viidete loendur (strong count): suureneb std::shared_ptr loomisel või kopeerimisel, väheneb hävitamisel. Kui see loendur jõuab nulli, vabastatakse hallatav objekt.
  2. Nõrkade viidete loendur (weak count): suureneb std::weak_ptr loomisel std::shared_ptr-st, väheneb hävitamisel. Juhtimisblokk vabastatakse, kui mõlemad loendurid — tugev ja nõrk — jõuavad nulli.

std::make_shared kasutamine on eelistatud otse new-i kasutamise ees, kuna see võib eraldada objekti ja juhtimisbloki ühes mälupunktis, parandades jõudlust ja vähendades fragmentatsiooni.

Aatomilised loendurid tagavad std::shared_ptr kasutamise ohutuse mitme niidi (multithreaded) stsenaariumites, kuigi hallatava objekti juurdepääs ei ole vaikimisi sünkroniseeritud.

Näide:

#include <iostream>
#include <memory>

struct MyObject {
    int data;
    MyObject(int d) : data(d) {
        std::cout << "MyObject(" << data << ") loodud\n";
    }
    ~MyObject() {
        std::cout << "MyObject(" << data << ") hävitatud\n";
    }
};

int main() {
    std::shared_ptr<MyObject> ptr1 = std::make_shared<MyObject>(10);
    // tugev loendur: 1, nõrk loendur: 0

    {
        std::shared_ptr<MyObject> ptr2 = ptr1;
        // tugev loendur: 2, nõrk loendur: 0

        std::weak_ptr<MyObject> weak_ptr = ptr1;
        // tugev loendur: 2, nõrk loendur: 1

        if (auto locked_ptr = weak_ptr.lock()) {
            // tugev loendur: 3, nõrk loendur: 1 (lock ajal)
            std::cout << "Objekti andmed: " << locked_ptr->data << std::endl;
        }
        // tugev loendur: 2, nõrk loendur: 1
    } // ptr2 väljub ulatusest
    // tugev loendur: 1, nõrk loendur: 1

    // Objekt pole veel hävitatud, kuna tugev loendur on 1

    {
        std::weak_ptr<MyObject> weak_ptr2 = ptr1;
        // tugev loendur: 1, nõrk loendur: 2
    } // weak_ptr2 väljub ulatusest
    // tugev loendur: 1, nõrk loendur: 1

} // ptr1 väljub ulatusest
// tugev loendur: 0, nõrk loendur: 1
// Objekt hävib, kuna tugev loendur sai 0
// Juhtimisblokk jääb alles kuni nõrk loendur jõuab 0-ni