Sobes.tech
Middle

Su quale base più oggetti shared_ptr possono fare riferimento allo stesso puntatore?

sobes.tech AI

Risposta dell'AI

Più oggetti std::shared_ptr possono fare riferimento allo stesso puntatore grazie alla presenza di un blocco di controllo (control block).

Il blocco di controllo associato all'oggetto gestito contiene:

  • Contatore di riferimenti forti (strong reference count): Aumenta quando si crea un nuovo shared_ptr per lo stesso oggetto. Diminuisce quando si distrugge un shared_ptr. Quando raggiunge zero, l'oggetto (puntatore) associato viene eliminato.
  • Contatore di riferimenti deboli (weak reference count): Usato per std::weak_ptr. Aumenta quando si crea un weak_ptr da un shared_ptr. Diminuisce quando si distrugge un weak_ptr. Quando entrambi i contatori sono zero, il blocco di controllo viene eliminato.
  • Puntatore proprio all'oggetto gestito: Non il puntatore ai dati stesso, ma quello gestito dal blocco.

Quando si crea un shared_ptr da un altro esistente (copia, assegnazione-copia), entrambi iniziano a usare lo stesso blocco di controllo, e il contatore di riferimenti forti in questo blocco aumenta.

Esempio:

#include <memory>
#include <iostream>

struct MyData {
    int value;
    MyData(int v) : value(v) { std::cout << "MyData(" << value << ") creato.\n"; }
    ~MyData() { std::cout << "MyData(" << value << ") distrutto.\n"; }
};

int main() {
    // Creazione del primo shared_ptr.
    // Creazione del blocco di controllo e dell'oggetto MyData.
    // Contatori: forte: 1, debole: 0.
    std::shared_ptr<MyData> ptr1 = std::make_shared<MyData>(10);
    std::cout << "conteggio di utilizzo di ptr1: " << ptr1.use_count() << "\n";

    // Creazione di un secondo shared_ptr da ptr1.
    // Usa lo stesso blocco di controllo.
    // Il contatore forte aumenta a 2.
    std::shared_ptr<MyData> ptr2 = ptr1;
    std::cout << "conteggio di utilizzo di ptr1: " << ptr1.use_count() << "\n";
    std::cout << "conteggio di utilizzo di ptr2: " << ptr2.use_count() << "\n";

    // Creazione di un terzo shared_ptr da ptr1.
    // Usa lo stesso blocco di controllo.
    // Il contatore forte aumenta a 3.
    std::shared_ptr<MyData> ptr3 = ptr1;
     std::cout << "conteggio di utilizzo di ptr1: " << ptr1.use_count() << "\n";
    std::cout << "conteggio di utilizzo di ptr2: " << ptr2.use_count() << "\n";
    std::cout << "conteggio di utilizzo di ptr3: " << ptr3.use_count() << "\n";

    std::cout << "Uscita dallo scope.\n";
    // ptr3 esce dallo scope.
    // Il contatore forte diminuisce a 2.
    // ptr2 esce dallo scope.
    // Il contatore forte diminuisce a 1.
    // ptr1 esce dallo scope.
    // Il contatore forte diminuisce a 0.
    // L'oggetto MyData viene distrutto.
    // Il blocco di controllo viene eliminato.
}

Ogni oggetto shared_ptr contiene il proprio puntatore al blocco di controllo e il proprio puntatore all'oggetto dati. Quando si copia un shared_ptr, entrambi i puntatori vengono copiati, e il contatore di riferimenti forti nel blocco comune aumenta. In questo modo, tutti i shared_ptr puntano allo stesso blocco di controllo, che tiene traccia del numero di copie che possiedono la risorsa e determina il momento di distruzione della risorsa gestita.