Programmation • IoT

Résumé – Chap 5 – std::shared_ptr et std::weak_ptr

std::unique_ptr convient lorsqu’une ressource possède un seul propriétaire, mais certaines architectures nécessitent que plusieurs objets partagent réellement la propriété d’une même ressource. std::shared_ptr répond à cette situation : plusieurs shared_ptr peuvent désigner le même objet et chacun participe à sa propriété. Contrairement à unique_ptr, un shared_ptr peut donc être copié. La durée de vie de la ressource est alors déterminée par un mécanisme de comptage de références : la création d’un nouveau propriétaire augmente le compteur et la disparition d’un propriétaire le diminue. Tant que ce compteur reste supérieur à zéro, la ressource continue d’exister ; lorsqu’il atteint zéro, elle est automatiquement détruite. use_count() permet d’observer ce nombre de propriétaires et std::make_shared permet de construire directement un objet géré par shared_ptr. Ce mécanisme s’appuie sur un bloc de contrôle commun aux différents shared_ptr, qui contient notamment les informations nécessaires au comptage. Cette gestion possède donc un coût supplémentaire par rapport à la propriété exclusive : shared_ptr n’est pas une version plus puissante de unique_ptr, mais un outil répondant à un modèle de propriété différent. Lorsque la propriété exclusive suffit, unique_ptr reste généralement le choix naturel.

Le comptage de références possède cependant une faiblesse importante : les références circulaires. Si deux objets gérés par shared_ptr possèdent chacun un shared_ptr vers l’autre, chacun maintient artificiellement l’autre en vie. Lorsque les propriétaires extérieurs disparaissent, les compteurs peuvent alors rester supérieurs à zéro et les objets ne sont jamais détruits, ce qui provoque une fuite de ressources. std::weak_ptr permet de rompre ce cycle en représentant une relation d’observation sans propriété. Un weak_ptr peut désigner une ressource gérée par shared_ptr sans augmenter son nombre de propriétaires et ne participe donc pas à sa durée de vie. La fonction expired() permet de savoir si la ressource observée existe encore, tandis que lock() tente d’obtenir un shared_ptr valide vers celle-ci. Si la ressource existe, ce shared_ptr temporaire en garantit la durée de vie pendant son utilisation ; sinon, il est vide. Les trois pointeurs intelligents expriment ainsi trois relations fondamentales : unique_ptr correspond à la propriété exclusive, shared_ptr à la propriété partagée et weak_ptr à l’observation sans propriété. Leur rôle ne consiste donc pas seulement à automatiser new et delete, mais surtout à rendre explicites les relations de propriété et de durée de vie entre les objets d’un programme.