Partage
  • Partager sur Facebook
  • Partager sur Twitter

Je ne comprends pas l'intérêt des weak_ptr

    4 octobre 2023 à 22:48:44

    Salut tout le monde !

    Je viens de lire C++ Primer et Effective Modern C++ et je n'y comprends vraiment rien aux weak_ptr.

    Je pense que mon problème vient surtout du fait que je ne vois pas à quel moment ils sont utiles.

    J'ai bien compris qu'ils permettent de manipuler indirectement des shared_ptr pour vérifier s'ils danglent ou pas mais je ne vois pas dans quel contexte cela s'applique.

    Dans Effective Modern C++ il y a 2 exemples mais ils sont trop abstraits et je n'ai pas réussi à me les représenter concrètement même en essayant de les implémenter moi-même dans mon IDE.

    Dans Effective Modern C++ il y a plusieurs phrases du genre :

    "You may be wondering how a std::weak_ptr could be useful."

     "you’re probably still wondering about how std::weak_ptrs can be useful"

    Ces phrases décrivent effectivement ma perplexité.

    Quelqu'un s'en est déjà servi ? J'ai passé tellement de temps à simplement essayer de leur trouver un cas d'utilisation que je commence à désespérer. :(

    • Partager sur Facebook
    • Partager sur Twitter
      4 octobre 2023 à 23:47:43

      Un exemple simple. Si tu veux implémenter une liste doublement chainée. Classiquement, on pourrait écrire :

      struct Node {
          Node* previous = nullptr;
          Node* next = nullptr;
      };
      
      int main() {
          // create 3 nodes
          Node* list = new Node;
          list.next = new Node;
          list.next.previous = list;
          list.next.next = new Node;
          list.next.next.previous = list.next;
      
          // delete
          delete list.next.next;
          delete list.next;
          delete list;
      }   

      Avec des shared_ptr :

      struct Node {
          std::shared_ptr<Node> previous;
          std::shared_ptr<Node> next;
      };
      
      int main() {
          // create 3 nodes
          Node* list = std::make_shared<Node>;
          list.next = std::make_shared<Node>;
      list.next.previous = list; list.next.next = std::make_shared<Node>;
      list.next.next.previous = list.next; // force delete list list.release(); }

      Le problème ici est que chaque node est propriétaire d'un autre node. Donc quand la liste est libéré, le premier node est géré par `list` (ce qui est release) et par le second (dans `previous`). Donc le node est pas détruit, puisqu'il existe encore un propriétaire. Idem pour les 2 autres nodes.

      Ce qu'on veut, c'est que `next` soit propriétaire, mais pas `previous`. Mais on veut quand même pouvoir utiliser `previous`, ce qui impose que `previous` soit propriétaire de temps en temps. C'est le rôle de std::weak_ptr.

      struct Node {
          std::weak_ptr<Node> previous;
          std::shared_ptr<Node> next;
      };

      Et pour accéder à `previous`, on le lock temporairement.

      if (std::shared<Node> locked_node = node.previous.lock()) {
          // use locked_node
      }
      • Partager sur Facebook
      • Partager sur Twitter
        5 octobre 2023 à 10:46:57

        Ah oui je comprends mieux maintenant ! Merci mille fois ! :)

        C'est plutôt malin en effet. Tu ne donnes la propriété du pointeur qu'à un seul objet comme ça si tu supprimes cet objet tu t'assures de supprimer tous les autres.

        Très malin ! :pirate:

        • Partager sur Facebook
        • Partager sur Twitter
          5 octobre 2023 à 18:44:29

          Je rebondis un peu sur le sujet.

          Et si au lieu de mettre un weak_ptr on mettait un pointeur nu ? (ou alors une classe qui encapsule un pointeur nu mais qui ne libere rien si vous n'aimez pas), quelles seraient les différences avec weak_ptr ?

          Si je fais pointer un weak sur un shared, puis que je perds le shared, alors la ressource sous le shared est désallouée. Que dit alors le weak_ptr si je l'interroge ?

          (le pointeur nu lui, pointerait sur une zone mémoire qui n'existe plus !)

          -
          Edité par Fvirtman 5 octobre 2023 à 18:45:00

          • Partager sur Facebook
          • Partager sur Twitter

          Recueil de code C et C++  http://fvirtman.free.fr/recueil/index.html

            5 octobre 2023 à 18:56:02

            Avec un pointeur nu, tu peux pas savoir si la ressource est libérée. Donc potentiellement un dangling pointer. 

            Un std::waek_ptr ne peut pas être utilisé directement. Il faut le lock, ce qui permet de vérifier que le pointeur est toujours valide et va créer un std::shared_ptr (et donc garantir que l'objet ne sera pas libéré après le lock).

            if (std::shared<Node> locked_node = node.previous.lock()) {
                // use locked_node
            }

            C'est particulièrement important dans un contexte multi threads.

            • Partager sur Facebook
            • Partager sur Twitter

            Je ne comprends pas l'intérêt des weak_ptr

            × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
            × Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
            • Editeur
            • Markdown