Pointeurs intelligents en C++

Introduction aux Pointeurs Intelligents

Un pointeur intelligent est une classe qui gère un pointeur à l'aide d'une technique connue sous le nom de "Resource Acquisition is Initialization" (RAII). Ce mécanisme permet aux développeurs de se décharger de la gestion manuelle de la mémoire, rendant ainsi la gestion des ressources plus sûre et moins susceptible d'entraîner des fuites mémoire en cas d'exceptions.

Propriété et gestion de la mémoire

Lorsqu'on parle de mémoire, la notion de propriété répond à la question : "Qui est responsable de la libération de la ressource ?" En C++, on trouve trois types de pointeurs intelligents standard, définis dans le fichier d'en-tête:

  1. std::unique_ptr : Ce pointeur détient la propriété exclusive d'une ressource. Elle s'assure que la mémoire est libérée lorsque l'objet atteint la fin de sa portée.
  2. std::shared_ptr : Ce pointeur partage la propriété d'une ressource. La mémoire ne sera libérée que lorsque toutes les copies du pointeur auront été détruites.
  3. std::weak_ptr : Ce pointeur est utilisé avec un shared pointer. Il ne contribue pas au compteur de références comme le fait un shared pointer.

Création de Pointeurs Intelligents

Les pointeurs intelligents peuvent être créés facilement en utilisant les fonctions suivantes : - Pour un unique_ptr, on utilise std::make_unique<T>(valeur). - Pour un shared_ptr, on appelle std::make_shared<T>(valeur).

Exemples de Pointeurs Intelligents

Pointeur Unique :

#include 
#include 

int main() {
    auto ptr = std::make_unique(10);
} // Le ptr atteint la fin de sa portée, pas de fuites mémoire

Pointeur Partagé :

#include 
#include 

int main() {
    auto ptr = std::make_shared(10);
    std::cout << ptr.use_count() << "\n"; // Affiche le compteur de références (1)
    {
        auto ptr2 = ptr; // Compteur de références à 2
        std::cout << ptr2.use_count() << '\n'; // Affiche le compteur de références (2)
    } // Le ptr2 atteint la fin de sa portée, le compteur de références est à 1, donc la ressource n'est pas libérée
    std::cout << *ptr << "\n";
} // Le ptr atteint la fin de sa portée, le compteur de références est à 0 donc la ressource est libérée

Sécurité des Exceptions

Voici un exemple de gestion des exceptions avec des pointeurs intelligents :

#include 
#include 

void unsafe_pointer() {
    int* ptr = new int(10);
    if (*ptr == 10) {
        throw;
    }
    delete ptr; // Le ptr n'est pas libéré
}

void safe_pointer() {
    auto ptr = std::make_unique(10);
    if (*ptr == 10) {
        throw;
    }
} // Le ptr est libéré à la sortie de la portée