Programmation • IoT

Chap 4 – std::unique_ptr en pratique

Après l’étude de la sémantique de déplacement, std::unique_ptr peut être utilisé pleinement comme outil de gestion d’une ressource à propriétaire unique. La création d’un objet dynamique se fait généralement avec std::make_unique, qui construit l’objet et confie immédiatement sa propriété au unique_ptr. L’accès à la ressource reste proche de celui d’un pointeur classique, avec * pour accéder à l’objet et -> pour accéder à ses membres. La différence essentielle concerne la propriété : un unique_ptr ne peut pas être copié, mais sa ressource peut être transférée avec std::move. Après ce transfert, le unique_ptr destination devient propriétaire et le pointeur source est vide. Cette propriété permet de faire apparaître directement dans le code la responsabilité de la durée de vie d’une ressource. Lorsqu’une fonction doit seulement utiliser l’objet sans en prendre possession, elle peut recevoir l’objet par référence ; lorsqu’elle doit au contraire devenir propriétaire, elle peut recevoir le unique_ptr par valeur. Un unique_ptr peut également être retourné par une fonction : la propriété de la ressource est alors transmise à l’appelant, sans qu’il soit nécessaire d’écrire explicitement std::move dans l’instruction return.

Plusieurs fonctions membres permettent d’agir sur cette propriété. get() fournit le pointeur brut vers la ressource sans en modifier le propriétaire, tandis que reset() détruit la ressource actuellement possédée et peut éventuellement en attribuer une nouvelle au unique_ptr. release() possède un rôle très différent : il abandonne la propriété et retourne le pointeur brut sans détruire la ressource ; le programmeur redevient alors responsable de sa libération. Un unique_ptr peut également gérer un tableau dynamique avec std::unique_ptr<T[]> et std::make_unique<T[]>, la destruction correcte du tableau étant automatiquement assurée. Cette possibilité ne signifie cependant pas qu’elle doive remplacer systématiquement les tableaux dynamiques manuels : pour une collection dynamique, std::vector est généralement plus approprié puisqu’il connaît sa taille et fournit les opérations propres à un conteneur. De même, tous les objets n’ont pas à être créés dynamiquement avec make_unique : lorsqu’un objet peut naturellement vivre dans sa portée, un objet automatique reste plus simple et évite une allocation et une indirection inutiles. Le pointeur brut et unique_ptr conservent ainsi des rôles distincts : le premier peut simplement désigner un objet sans le posséder, tandis que le second exprime explicitement la propriété exclusive et la responsabilité de sa destruction.