Introduction : Pourquoi votre programme a-t-il "mangé" toute la mémoire et comment y remédier ?
\n\nAvez-vous déjà écrit une application en C++ qui fonctionnait parfaitement jusqu'à ce que vous fermiez la fenêtre ? Pour ensuite découvrir qu'elle avait "mangé" un gigaoctet de RAM sans en rendre un seul octet ? Ou, pire encore, votre programme plantait soudainement avec un mystérieux segmentation fault, et vous passiez des heures à chercher où vous aviez oublié d'appeler delete ?
Si oui — bienvenue au club. La gestion manuelle de la mémoire en C++, c'est un peu comme jongler avec des tronçonneuses : c'est possible, mais mieux vaut laisser ça aux professionnels. Ou, dans notre cas, aux pointeurs intelligents (smart pointers).
\n\nAujourd'hui, nous allons voir ce que sont ces bestioles, quels types existent et, surtout, quand utiliser lequel. Ce contenu est une adaptation de la célèbre question sur Stack Overflow qui a recueilli des milliers de vues. Nous allons la rendre claire, vivante et avec des exemples. C'est parti !
\n\nQu'est-ce qu'un pointeur intelligent ? En termes simples
\n\nImaginez un pointeur ordinaire (int* ptr = new int(5);). C'est comme une clé d'un placard à ressources. Vous ouvrez le placard (vous allouez de la mémoire), mais si vous perdez la clé ou oubliez de fermer la porte, les ressources disparaissent à jamais. C'est ce qu'on appelle une fuite de mémoire.
Un pointeur intelligent est une "clé à fermeture automatique". C'est une classe d'encapsulation qui stocke un pointeur ordinaire à l'intérieur et appelle automatiquement delete (ou delete[]) lorsque l'objet n'est plus nécessaire. Lorsque le pointeur intelligent sort de la portée, son destructeur se déclenche et libère la mémoire. De la magie ? Non, c'est le RAII (Resource Acquisition Is Initialization) — l'un des piliers du C++.
Depuis C++11, les pointeurs intelligents font partie de la bibliothèque standard (<memory>). Oubliez auto_ptr (il est obsolète et dangereux). Nous avons désormais trois mousquetaires :
- \n
std::unique_ptr— le propriétaire unique. \n std::shared_ptr— la ressource en "propriété collective". \n std::weak_ptr— l'"observateur" qui ne gêne pas. \n
Examinons chacun d'eux simplement et avec du code.
\n\nstd::unique_ptr : "C'est à moi, et à personne d'autre !"
\n\nstd::unique_ptr est le pointeur intelligent le plus simple et le plus rapide. Il garantit que la propriété de l'objet appartient à un seul pointeur. Vous ne pouvez pas copier un unique_ptr, mais vous pouvez le déplacer (transférer la propriété).
Quand l'utiliser ? Presque toujours lorsque vous créez un objet sur le tas et que vous savez qu'il aura un seul propriétaire tout au long de sa vie.
\n\nExemple : Création et utilisation
\n\n#include <iostream>\n#include <memory> // pour les pointeurs intelligents\n\nclass Robot {\npublic:\n Robot(const std::string& name) : name_(name) {\n std::cout << "Robot " << name_ << " activé !\\n";\n }\n void speak() const { std::cout << name_ << " : Bonjour le monde !\\n"; }\n ~Robot() { std::cout << "Robot " << name_ << " détruit.\\n"; }\nprivate:\n std::string name_;\n};\n\nint main() {\n // Création d'un unique_ptr (n'utilisez jamais new !)\n std::unique_ptr<Robot> r1 = std::make_unique<Robot>("R2-D2");\n\n r1->speak(); // On travaille comme avec un pointeur ordinaire\n\n // std::unique_ptr<Robot> r2 = r1; // Erreur ! Impossible de copier\n std::unique_ptr<Robot> r2 = std::move(r1); // Transfert de propriété\n\n if (!r1) {\n std::cout << "r1 est maintenant vide, la propriété a été transférée à r2\\n";\n }\n\n r2->speak(); // Fonctionne\n // Ici, r2 sort de la portée et le robot est automatiquement détruit\n return 0;\n}\n\nImportant : Utilisez std::make_unique<T>(args...) au lieu de new