Sobes.tech
Middle

Sur quelle base plusieurs objets shared_ptr peuvent-ils faire référence au même pointeur?

sobes.tech IA

Réponse de l'IA

Plusieurs objets std::shared_ptr peuvent faire référence au même pointeur grâce à l'existence d'un bloc de contrôle (control block).

Le bloc de contrôle associé à l'objet géré contient :

  • Compteur de références fortes (strong reference count) : Augmente lors de la création d'un nouveau shared_ptr pour le même objet. Diminue lors de la destruction d'un shared_ptr. Lorsqu'il atteint zéro, l'objet (pointeur) associé est supprimé.
  • Compteur de références faibles (weak reference count) : Utilisé pour std::weak_ptr. Augmente lors de la création d'un weak_ptr à partir d'un shared_ptr. Diminue lors de la destruction d'un weak_ptr. Lorsqu'ils atteignent tous deux zéro, le bloc de contrôle est supprimé.
  • Pointeur propre vers l'objet géré : Pas le pointeur de données lui-même, mais celui qui est géré par le bloc.

Lorsque vous créez un shared_ptr à partir d'un autre existant (copie, affectation-copie), ils commencent à utiliser le même bloc de contrôle, et le compteur de références fortes dans ce bloc augmente.

Exemple :

#include <memory>
#include <iostream>

struct MyData {
    int value;
    MyData(int v) : value(v) { std::cout << "MyData(" << value << ") créé.\n"; }
    ~MyData() { std::cout << "MyData(" << value << ") détruit.\n"; }
};

int main() {
    // Création du premier shared_ptr.
    // Création du bloc de contrôle et de l'objet MyData.
    // Compteurs strong : 1, weak : 0.
    std::shared_ptr<MyData> ptr1 = std::make_shared<MyData>(10);
    std::cout << "compteur d'utilisation de ptr1 : " << ptr1.use_count() << "\n";

    // Création d'un second shared_ptr à partir de ptr1.
    // Utilise le même bloc de contrôle.
    // Le compteur strong augmente à 2.
    std::shared_ptr<MyData> ptr2 = ptr1;
    std::cout << "compteur d'utilisation de ptr1 : " << ptr1.use_count() << "\n";
    std::cout << "compteur d'utilisation de ptr2 : " << ptr2.use_count() << "\n";

    // Création d'un troisième shared_ptr à partir de ptr1.
    // Utilise le même bloc de contrôle.
    // Le compteur strong augmente à 3.
    std::shared_ptr<MyData> ptr3 = ptr1;
     std::cout << "compteur d'utilisation de ptr1 : " << ptr1.use_count() << "\n";
    std::cout << "compteur d'utilisation de ptr2 : " << ptr2.use_count() << "\n";
    std::cout << "compteur d'utilisation de ptr3 : " << ptr3.use_count() << "\n";

    std::cout << "Sortie du scope.\n";
    // ptr3 sort de la portée.
    // Le compteur strong diminue à 2.
    // ptr2 sort de la portée.
    // Le compteur strong diminue à 1.
    // ptr1 sort de la portée.
    // Le compteur strong diminue à 0.
    // L'objet MyData est détruit.
    // Le bloc de contrôle est détruit.
}

Chaque objet shared_ptr contient son propre pointeur vers le bloc de contrôle et son propre pointeur vers l'objet de données. Lors de la copie d'un shared_ptr, les deux pointeurs sont copiés, et le compteur de références fortes dans le bloc commun est incrémenté. Ainsi, tous les shared_ptr pointent vers le même bloc de contrôle, qui suit le nombre de ses copies possédant la ressource et détermine le moment de destruction de la ressource gérée.