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:
- 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.
- 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.
- 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