Présentation de PImpl

PImpl (Pointer to implementation) est une technique de programmation qui permet de séparer les détails d'implémentation d'une classe en les plaçant dans une classe séparée, accessible via un pointeur opaque. Son objectif est de séparer les interfaces et les implémentations, et de minimiser les dépendances au moment de la compilation.

Implémentation avec un pointeur brut

L'implémentation de PImpl peut être réalisée à l'aide de pointeurs bruts et en suivant la règle des cinq. Cette règle stipule que lorsqu'une classe définit une fonction membre spéciale (pour la gestion des ressources), elle doit définir les cinq fonctions suivantes : destructeur, constructeur de copie, opérateur d'affectation de copie, constructeur de déplacement et opérateur d'affectation de déplacement.

struct Widget::Impl
   {
       std::string name;
       int         clicks = 0;
       explicit Impl(std::string n) : name(std::move(n)) {}
   };
   Widget::Widget(const std::string& name)
       : pimpl_(new Impl(name))
   {
   }

Cependant, cette implémentation présente des problèmes, tels que la non-propagation de la constance de Widget à Impl, et le risque de comportement indéfini lors de l'utilisation d'un objet déplacé.

Implémentation avec std::unique_ptr

L'utilisation de std::unique_ptr peut simplifier l'implémentation en gérant automatiquement l'objet alloué, ce qui élimine la nécessité d'une gestion manuelle des ressources.

class Widget 
   {
   public:
       // ...
   private:
       struct Impl;
       std::unique_ptr pimpl_;
   };
   Widget::Widget(const std::string& name)
       : pimpl_(std::make_unique(name)) 
   {
   }

Cependant, les problèmes de constance et de nullité persistent.

Implémentation avec std::indirect

Le type std::indirect, introduit dans C++26, est conçu pour être utilisé pour les membres de classe alloués dynamiquement mais qui doivent se comporter comme des valeurs. Il est destiné à remplacer std::unique_ptr lorsque ses sémantiques (non copiable, ne propage pas la constance et peut être nul) ne sont pas appropriées.

Il s'agit d'un exemple parfait pour l'implémentation de PImpl, car il permet de résoudre les problèmes de constance et de nullité tout en simplifiant l'implémentation.