Sobes.tech
Middle

Jak działa shared_ptr w C++?

sobes.tech AI

Odpowiedź od AI

shared_ptr — to inteligentny wskaźnik implementujący semantykę własności współdzielonego zasobu. Przechowuje wskaźnik na obiekt i wskaźnik na blok kontrolny.

Blok kontrolny zawiera:

  • Licznik silnych odwołań (reference count).
  • Licznik słabych odwołań (weak count).
  • Niestandardowy funktor usuwania (deleter), jeśli jest ustawiony.
  • Niestandardowy alokator, jeśli jest ustawiony.
  • Wskaźnik na przechowywany obiekt (ten sam, co w shared_ptr).

Zasada działania:

  1. Tworzenie: Przy tworzeniu pierwszego shared_ptr wskazującego na obiekt, tworzony jest blok kontrolny, a liczniki odwołań są inicjalizowane: silne — 1, słabe — 0.
    std::shared_ptr<int> ptr1 = std::make_shared<int>(10); // Tworzy obiekt int i blok kontrolny
    
  2. Kopiowanie: Przy kopiowaniu shared_ptr licznik silnych odwołań w bloku kontrolnym zwiększa się o 1.
    std::shared_ptr<int> ptr2 = ptr1; // Zwiększa licznik silnych odwołań
    
  3. Przypisanie: Przy przypisaniu shared_ptr stary zasób jest dekrementowany (licznik silnych odwołań maleje), a nowy zasób jest inkrementowany (zwiększa się).
    std::shared_ptr<int> ptr3;
    ptr3 = ptr1; // Dekrementuje stary zasób ptr3, Inkrementuje zasób ptr1
    
  4. Usuwanie: Przy niszczeniu shared_ptr (np. wyjście z zakresu) licznik silnych odwołań jest dekrementowany.
    {
        std::shared_ptr<int> ptr4 = ptr1; // Zwiększa licznik silnych odwołań
        // ptr4 wychodzi z zakresu
    } // Dekrementuje licznik silnych odwołań
    
  5. Zwolenienie zasobu: Gdy licznik silnych odwołań osiąga zero, zasób (obiekt, na który wskazuje shared_ptr) jest usuwany za pomocą zdefiniowanego funktora usuwania (lub delete domyślnie).
  6. Zwolenienie bloku kontrolnego: Blok kontrolny jest zwalniany, gdy oba liczniki (silne i słabe) osiągają zero.

Zalety:

  • Automatyczne zarządzanie pamięcią dla zasobów współdzielonych.
  • Bezpieczeństwo przed podwójnym zwolnieniem.
  • Obsługa niestandardowych funktorów usuwania.

Wady:

  • Cycliczne odwołania mogą prowadzić do wycieków pamięci (rozwiązane za pomocą weak_ptr).
  • Niewielki wzrost kosztów z powodu bloku kontrolnego i operacji atomowych na licznikach.
  • Bezpieczeństwo operacji z samym shared_ptr (kopiowanie, przypisanie, zmiana wskaźnika), ale nie z obiektem, na który wskazuje.