Partage
  • Partager sur Facebook
  • Partager sur Twitter

Comment nodiscard fonctionne ?

Sujet résolu
    11 mai 2022 à 13:50:47

    Salut

    Grace a un sujet atif ici j'ai lu ceci: Message de @Koala - Discussion @JadeSalina

    Il dit que nodiscard dit au compilateur que le retour de la fonction dot imperativement etre recuperer et je voudrais savoir comment, ou plutot pourquoi ce mot-cle.

    Si je fait une fonction

    int maFonction(){
        return 1;
    } 

    Que peut-il arriver pour que le retour de ma fonction soit pas recu ? Si je ne retourne rien le compilateur m'avertira.

    Il peut donc arriver que mon code continue a s'executer si par exemple int a = maFonction() ne fait rien, y'aura pas une erreur par defaut?? Si non dans quels cas car je ne vois qu'un mechant bug cote memoire et y'a tres peu de chance que cela survienne sur nos nouvelles machines.

    Merci.

    • Partager sur Facebook
    • Partager sur Twitter
      11 mai 2022 à 14:06:54

      nodiscard sert à "obliger" à utiliser le retour d'une fonction (ou d'un type).

      int foo() { return 1; }
      [[nodiscard]] int bar() { return 1; }
      
      int main() {
          foo(); // ok
          bar(); // warning
          auto f = foo(); // ok
          auto b = bar(); // ok
      }

      L'utilité de cette fonctionnalité vient d'un vieux problème : quelle est la meilleure façon de gérer les erreurs ? En C++, il y a plusieurs méthodes utilisables (retour d'un code d'erreur, exception, retourner un objet invalide, etc). L'une des critiques faite au retour d'un code d'erreur, c'est que l'utilisateur n'est pas obligé de vérifier les erreurs.

      Une exemple de comment il faudrait gérer correctement un code avec retour d'erreur : https://alexandre-laurent.developpez.com/cpp/retour-fonctions-ou-exceptions/

      C'est pour ça qu'on conseille souvent les méthodes qui obligent les devs à vérifier les erreurs. C'est le fameux principe que koala01 a rappelé : "Make things (interfaces) easy to use correctly and hard to use incorrectly". Avec des exceptions, les utilisateurs n'ont pas d'autres choix que d'utiliser correctement une interface, contrairement au retour d'erreur qui autorise les devs à ignorer les erreurs.

      Mais les exceptions ne sont pas un mécanisme parfait (il n'existe pas de système de gestion des erreurs parfait). Pour ça que certains ont demandé un mécanisme qui force à ne pas ignorer les retours d'erreur. C'est le rôle de nodiscard. (En pratique, ils peuvent quand même les ignorer. Mais c'est un choix volontaire de leur part dans ce cas).

      -
      Edité par gbdivers 11 mai 2022 à 14:08:01

      • Partager sur Facebook
      • Partager sur Twitter
        11 mai 2022 à 15:30:48

        Merci pour l'explication.

        Et apres avoir lu le contenu de ton lien, je prefere vraiment les exceptions(ancienne approche), vu que je connais rien a ce "RAII". C'est tres instructif en tout cas.


        Mon probleme est resolu mais j'ai une autre question s'il vous plait, je voudrais pas creer un nouveau sujet juste pour ca: goto est il proscrit en C++ ?

        Je me souviens(et je me trompes peut-etre) avoir utilisé goto dans un code c ou c++ il y'a 1 ou 2 ans et vous(les membres du forum) m'avez conseillé de ne pas l'utiliser. Bon c'etait pas directemet dit ainsi mais vous m'avez donné des moyens de contourner le goto avec des while et autres. Je ne retrouve pas le sujet en question mais je me demande toujours pourquoi ces recommandations.Je ne m'en sers plus depuis mais je veux bien savoir. Utiliser goto, qui parait plutot simple, n'est pas une bonne chose ? Ou alors quand est-il preferable de l'utiliser ?

        Petit truc extrait du lien:Assurez-vous qu'il n'y ait pas de 'goto' : ils cassent les destructeurs C++. Vous pouvez aussi developper ceci s'il vous plait ?

        -
        Edité par Asmitta 11 mai 2022 à 15:32:20

        • Partager sur Facebook
        • Partager sur Twitter
          11 mai 2022 à 15:46:40

          goto facilite la création du code spaghetti, c'est à dire du code peu structuré et plus difficile à comprendre. Les structures de controles (for, while, etc) et plus généralement, le code structuré, facilite la comprehension. 

          En C (mais je ne code pas dans ce langage), il me semble que goto est utilisé pour la gestion des erreurs (mais c'est que des goto internes dans une fonction)

          Je n'ai jamais utilisé goto dans un code pro ou personnel.

          Pour les destructeurs, je n'utilise pas goto, donc je sais pas trop. A ma connaissance, ca pose pas de problème, mais je laisse les autres répondre sur ce point.

          • Partager sur Facebook
          • Partager sur Twitter
            11 mai 2022 à 15:49:42

            `[[nodiscard]]` est hyper utile dans des lib mathématiques où à cause des 150k API différentes on peut ne pas savoir si une fonction membre renvoie une nouvelle valeur ou au contraire mute l'objet courant.

            Typiquement: `Vector_kD::negate()`, ça fait quoi? Dans le cas nouvelle valeur, il est alors impossible de se tromper car le compilateur va nous gueuler dessus si on appelle v.negate() sans stocker le résultat.

            Le coût ?
            - A la compilation? -> probablement.
            - A l'exécution? -> aucune.
            - A l'écriture de code ?-> quelques mots à taper en plus, et des baffes à la compilation en cas d'erreur

            Bilan?
            --> que du positif en ce qui me concerne.

             -------------------

            EDIT: Aucun intérêt à goto en C++. En C il est quasi-nécessaire pour les zones de restitution de ressources en cas d'erreur. Sachant qu'il reste complexe et vite mal employé (cf bug "récent" chez Toyota, IIRC). En C++ on a le RAII pour garantir la restitution des ressources quel que soit le chemin pris. Les derniers cas d'utilisation "tolérables" de goto en C++ c'est pour sauter en avant pour sortir de boucles. Mais on a mieux: break, continue, ou carrément l'écriture de petites fonctions (typiquement de recherche) depuis lesquelles on sortira prématurément avec des returns, ce qui permet de gérer la double boucle.

            -
            Edité par lmghs 11 mai 2022 à 15:56:28

            • Partager sur Facebook
            • Partager sur Twitter
            C++: Blog|FAQ C++ dvpz|FAQ fclc++|FAQ Comeau|FAQ C++lite|FAQ BS| Bons livres sur le C++| PS: Je ne réponds pas aux questions techniques par MP.
              11 mai 2022 à 16:01:13

              gbdivers a écrit:

              goto facilite la création du code spaghetti, c'est à dire du code peu structuré et plus difficile à comprendre.


              Comme en assembleur ? C'est le premier langage que ou j'ai vu goto (pas clairement, c'etait MOV je crois).

              lmghs a écrit:

              `[[nodiscard]]` est hyper utile dans des lib mathématiques où à cause des 150k API différentes on peut ne pas savoir si une fonction membre renvoie une nouvelle valeur ou au contraire mute l'objet courant.


              Je vois mieux son utilité Merci.


              Bon je reste legerement sur ma faim ( Assurez-vous qu'il n'y ait pas de 'goto' : ils cassent les destructeurs C++. ) mais Merci pou vos reponses

              -
              Edité par Asmitta 11 mai 2022 à 16:02:23

              • Partager sur Facebook
              • Partager sur Twitter
                11 mai 2022 à 16:05:00

                Asmitta a écrit:

                Bon je reste legerement sur ma faim ( Assurez-vous qu'il n'y ait pas de 'goto' : ils cassent les destructeurs C++. ) mais Merci pou vos reponses

                https://stackoverflow.com/questions/3179936/goto-out-of-a-block-do-destructors-get-called

                Quant à goto, ça me rappelle surtout mes années BASIC, et je ne suis pas particulièrement nostalgique du langage...

                • Partager sur Facebook
                • Partager sur Twitter
                C++: Blog|FAQ C++ dvpz|FAQ fclc++|FAQ Comeau|FAQ C++lite|FAQ BS| Bons livres sur le C++| PS: Je ne réponds pas aux questions techniques par MP.
                  11 mai 2022 à 16:12:37

                  > goto est il proscrit en C++ ?

                  Pas spécialement, mais son besoin en C++ est fortement réduit, presque inexistant. En C, on en met pas mal pour gérer le nettoyage des ressources en cas d'erreur: la fonction échoue, il faut libérer la mémoire des objets intermédiaire. En C++, on se base sur le RAII, la fonction échoue, on en sort et les destructeurs libèrent d'eux-mêmes la mémoire.

                  > Assurez-vous qu'il n'y ait pas de 'goto' : ils cassent les destructeurs C++.

                  C'est faux. Je ne sais pas pourquoi certaines personnes ont cette idée en tête... Peut-être de vieux bug dans les vieux compilateurs ?

                  En tout cas, la doc de goto est claire, tous les destructeurs sont appelés si on sort des scopes avec goto. Mais il y a des limitations qui empêchent le code de compiler lorsqu'on construit et/ou initialise des variables: https://en.cppreference.com/w/cpp/language/goto

                  Concernant nodiscard, je n'aime pas l'utilisé sur le retour des fonctions, cela rend le code verbeux. Si possible, je préfère avoir des types dédiés catégorisé nodiscard. Cela allège le code et accentue l'information sur le type.

                  -
                  Edité par jo_link_noir 11 mai 2022 à 16:17:30

                  • Partager sur Facebook
                  • Partager sur Twitter
                    11 mai 2022 à 16:24:24

                    lmghs a écrit:

                    https://stackoverflow.com/questions/3179936/goto-out-of-a-block-do-destructors-get-called.


                    jo_link_noir a écrit:

                    > Assurez-vous qu'il n'y ait pas de 'goto' : ils cassent les destructeurs C++.

                    C'est faux. Je ne sais pas pourquoi certaines personnes ont cette idée en tête... Peut-être de vieux bug dans les vieux compilateurs ?

                    En tout cas, la doc de goto est claire, tous les destructeurs sont appelés si on sort des scopes avec goto. Mais il y a des limitations qui empêchent le code de compiler lorsqu'on construit et/ou initialise des variables: https://en.cppreference.com/w/cpp/language/goto


                    Merci ^^
                    • Partager sur Facebook
                    • Partager sur Twitter
                      11 mai 2022 à 16:56:27

                      Asmitta a écrit:

                      Merci pour l'explication.

                      Et apres avoir lu le contenu de ton lien, je prefere vraiment les exceptions(ancienne approche), vu que je connais rien a ce "RAII". C'est tres instructif en tout cas.

                      Tu aurais vraiment intérêt à passer à la gestion des exceptions avec RAII.

                      Car, en fait, ce que fait le RAII est finalement tout bête: il s'assure que n'importe quelle ressource demandée (et obtenue) sera effectivement libérée au mieux quand on n'en aura plus besoin, au pire, lorsque l'on perdra "toute référence" pour la ressource en question.

                      Autrement dit, si une ressource -- quelle qu'elle soit -- est prise en charge par le RAII, tu as la certitude qu'elle ne sera pas "oubliée dans un coin", à se morfondre toute seule dans le noir en attendant un usage qui n'aura plus lieu, et qu'elle sera au contraire correctement libérée "dés que cela aura du  sens de le faire".

                      De plus, il est relativement facile de mettre en place l'utilisation du RAII, car la bibliothèque standard nous offre deux possibilités (représentées par trois classes, assez bizarrement :D):

                      La notion de possesseur unique : quand tu reçois une ressource (un pointeur sur n'importe quelle ressource), tu  la donnes à la classe unique_ptr qui en devient littéralement le "propriétaire légal": il n'y a plus qu'un seul élément qui peut décider de libérer la ressource, et c'est le unique_ptr.

                      Et comme la libération de la ressource se fait automatiquement lorsque le unique_ptr est détruit, le simple fait de quitter la portée dans laquelle un unique_ptr est connu (ce qui  fait que l'on perd la référence à la ressource qu'il contient) provoque forcément la libération de la ressource.

                      Tu n'as donc pas à t'inquiéter de cette ressource: si tu dispose du unique_ptr qui a la charge de la ressource (et que tu n'a pas invalidé cette ressource entre temps), c'est que la ressource est disponible.  Sinon, ben, tu n'as sans doute pas accès au unique_ptr en question ;)

                      La seule question à laquelle tu auras peut-être difficile à  répondre est : "à qui vais-je donner ce pointeur unique, pour qu'il puisse le garder tout le temps nécessaire en mémoire?"

                      La notion de pointeur partagé: Pour faire simple, on va dire que l'on peut éventuellement avoir plusieurs propriétaires pour une même ressource. En simplifiant au maxium, on pourrait dire que l'on va prendre le temps, à chaque fois que l'on défini un nouveau propriétaire pour cette ressource, d'incrémenter un compteur (dit "compteur de références") et, à chaque fois qu'un propriétaire actuel cessera d'exister, on va décrémenter ce compteur.

                      Ces "multiples propriétaires" sont représentés dans la bibliothèque standard sous  la forme de shared_ptr

                      Et, pour le reste, c'est un peu comme au bureau: le dernier éteint la lumière et ferme la porte :D.  Dans le cas présent, lorsque le dernier propriétaire disparait, il se charge de libérer la ressource ;)

                      Cependant, il arrive aussi que l'on veuille "faire voyager" la ressource. Mais c'est comme avec DPD: à aucun moment le chauffeur de DPD ne devient le propriétaire de ton colis: il en est juste le "dépositaire" et sa seule responsabilité est de le faire voyager (de préférence sans casse) d'un point à  un autre.

                      Le "chauffeur DPD" de la bibliothèque standard prend la forme d'un weak_ptr, c'est à dire d'une "capsule" qui peut se balader avec une ressource à gauche et à droite mais qui n'en est pas propriétaire, et qui est par contre capable de dire à n'importe quel moment si il existe toujours bel et bien au moins un propriétaire "vivant".

                      Parce que, tant qu'il y a un propriétaire vivant, la ressource est censée être disponible (à moins que tu n'aies fait une connerie, bien sur) et que, dés que le dernier "propriétaire légal" de la ressource aura disparu, la ressource sera réputée comme "étant devenue indisponible" ;)

                      Tu n'imagines pas la facilité -- mieux, la sécurité -- que ces deux notions peuvent apporter dans ton code.

                      Bien sur, il est possible et au demeurant très facile de faire "sensiblement pareil" par toi-même. Il est d'ailleurs beaucoup plus facile d'avoir un propriétaire unique pour une ressource que d'avoir des propriétaires multiples ;).

                      Si tu sais exactement ce que tu fais et que tu travailles avec une approche RAII cohérente, tu n'es bien sur pas impérativement tenu à utiliser std::unique_ptr ou std::shared_ptr.  Mais si tu as le moindre doute, cela restera quand même des "valeurs sures" ;)

                      Asmitta a écrit:

                      e voudrais pas creer un nouveau sujet juste pour ca: goto est il proscrit en C++ ?

                      Disons le tout de suite, avant que certians ne viennent pousser de hauts cris sur ce passage de mon intervention

                      Goto est comme toutes les autres techniques dont on peut disposer: il se peut qu'il soit intéressant -- voir indispensable -- de l'utiliser dans certaines situations très particulières.

                      Par contre, c'est une technique qui apporte tellement de "contre indications" et de "problèmes" que les bénéfices que l'on tire de son utilisation sont très souvent à ce point minimes qu'il vaut mieux l'éviter autant que  possible ;)

                      Asmitta a écrit:

                      Je me souviens(et je me trompes peut-etre) avoir utilisé goto dans un code c ou c++ il y'a 1 ou 2 ans et vous(les membres du forum) m'avez conseillé de ne pas l'utiliser. Bon c'etait pas directemet dit ainsi mais vous m'avez donné des moyens de contourner le goto avec des while et autres.

                      Ce serait tout à fait dans la "ligne de conduite" des gens de t'avoir déconseillé l'usage de goto ;)

                      Car il faut te mettre à  notre place: on est face à une technique

                      • qui présente énormément de problème lorsqu'elle est utilisée
                      • pour laquelle il excessivement long de te dresser le détail de tous les problèmes qu'elle implique
                      • dont il est particulièrement simple de se passer
                      • (et pour laquelle un prof m'a menacé de me faire passer par la fenêtre (du deuxième étage) si je l'utilisais avec lui :o:p)

                      Il est beaucoup plus facile pour nous de te dire simplement "attention, n'utilise pas ca, malheureux (ouh là là)" pour que tu apprennes à t'en passer, sans que l'on doive t'expliquer tous les tenants et les aboutissants et en arriver à un point où tu décidera quand même de l'utiliser au risque de te retrouver avec un "code spagetti" ;)

                      On pourrait bien sur préciser que "dans deux ou trois ans (voir plus), lorsque tu auras suffisamment de bouteille que pour comprendre tout ce qu'implique l'utilisation de cette instruction, tu pourras peut-être trouver un peu de temps pour t'intéresser aux quelques cas où son utilisation peut être intéressante".

                      Sauf que, tu auras sans doute tellement pris l'habitude de t'en passer que son utilisation ne te viendra très certainement pas à l'esprit comme "première solution envisageable" ;)

                      Savais tu d'ailleurs que  même Dennis Ritchie (l'un des créateurs du C) -- à moins que ce ne soit Bjarne Strutroup (le créateur du C++)? -- regrettait d'avoir introduit cette commande dans "son" langage?

                      C'est te dire à quel point cette "instruction pourtant si simple (et si utile ???)" et que l'on retrouve dans la grosse majorité des langages (de tous ceux que je connais, en tout cas) a pu pourrir la vie de générations entières de développeurs !

                      Alors, bien sur, tu feras au final ce que tu veux (tant que je suis pas ton chef technique, s'entend :D ), cependant, le  conseil qu'on t'a donné, il vaut son "pesant d'or" ;)

                      • Partager sur Facebook
                      • Partager sur Twitter
                      Ce qui se conçoit bien s'énonce clairement. Et les mots pour le dire viennent aisément.Mon nouveau livre : Coder efficacement - Bonnes pratiques et erreurs  à éviter (en C++)Avant de faire ce que tu ne pourras défaire, penses à tout ce que tu ne pourras plus faire une fois que tu l'auras fait
                        11 mai 2022 à 17:21:46

                        Plus je lis tes reponses plus je me rends compte qu'il va falloir que je devienne assez fort en francais pour pouvoir partager mes -maigres- connaissances a d'autres. Tu trouves disons les bonnes expressions a chaque fois et tes explications sont tres claires(pas comme pour certains de mes professeurs...).

                        std::unique_ptr, std::shared_ptr et std::weak_ptr sont donc dans la liste des classes a devoir manier plus tard, car actuellement faudrai d'abord que j'ai un code "efficace".

                         Thks

                        • Partager sur Facebook
                        • Partager sur Twitter
                          11 mai 2022 à 18:16:13

                          koala01 a écrit:

                          Autrement dit, si une ressource -- quelle qu'elle soit -- est prise en charge par le RAII, tu as la certitude qu'elle ne sera pas "oubliée dans un coin", à se morfondre toute seule dans le noir en attendant un usage qui n'aura plus lieu, et qu'elle sera au contraire correctement libérée "dés que cela aura du  sens de le faire".

                          J'espère que vous n'avez pas oublié un std::move quelque part, ce qui provoquerait une copie du std::shared_ptr et donc une non libération des ressources. C'est dommage car le compilateur ne pourra pas nous aider sur ce coup, et en plus le programme fonctionnera parfaitement aussi !! Mais tapie dans l'ombre se trouvera une pauvre ressource laissée à l'abandon que plus personne n'utilise et qui est triste toute seule :( (et qui bouffe notre mémoire cette sagouine)

                          Et les std::shared_ptr sont une implémentation d'un type de gestion mémoire qui s'appelle le reference counting. C'est une façon parmi d'autres de gérer la mémoire, ne croyez pas que c'est la seule façon (surtout dans les logiciels "critiques" ou à haute performance, style jeux vidéos). Voilà un exemple de gestion mémoire complètement différent des smart pointers et qui apporte son lot d'avantages : https://floooh.github.io/2018/06/17/handles-vs-pointers.html

                          Ca sera à vous de déterminer quelle solution est la plus appropriée selon la situation. Donc une fois que vous aurez appris à utiliser les smart pointers, le voyage ne sera pas fini, les smart pointers sont UNE façon de faire, parmi d'autres. Et ça vaut aussi pour la gestion d'erreurs, C++ propose sa "méthode idiomatique" (exceptions), mais ça veut pas dire que c'est la seule manière. A juger là aussi en fonction de la situation.

                          En parlant d'un std::move oublié, il y a un mec qui a codé un truc en utilisant std::accumulate (https://www.youtube.com/watch?v=mOSirVeP5lo&t=1575s). Pourquoi avoir utilisé std::accumulate au lieu de faire un truc comme ça ? 

                          Foo foo {};
                          
                          for (...) {
                              foo.blablabla += ceci_ou_cela; // on accumule un résultat dans foo
                          }
                          
                          return foo;

                          ça je n'ai pas la réponse. Peut être qu'il a jugé que std::accumulate avait une meilleure sémantique ? Oui je suis d'accord, mais encore faut-il savoir ce que fait cette fonction, selon les langages les notions de fold, reduce, ... ont quelques différences, donc cela oblige à aller voir la doc au lieu de directement voir la boucle et savoir ce qui se passe. D'autant plus que le fait d'appeler une fonction externe implique qu'il faut suivre ses évolutions en cas de mise à jour, ce qui est un peu dommage (alors que la simple boucle fait très bien le boulot et en plus est très lisible).

                          Bon tout ça pour dire que le mec a utilisé un std::accumulate et devinez quoi :) ? Avant C++20, std::accumulate passait la valeur accumulée par COPIE, ce qui fait que non content d'avoir un code potentiellement moins lisible (par rapport à la simple boucle), eh bien ça a été obligé de faire la copie du truc qu'il accumulait, qui contenait, manque de chance, un std::shared_ptr !! Donc à chaque itération, il fallait copier et détruire un std::shared_ptr. The Cherno a réécrit son truc en utilisant une boucle, et boum il est passé de 7min à 22sec d'exécution !! Donc il aurait été plus intéressant de faire une simple boucle dès le début au lieu d'avoir un résultat aussi pathétique (excusez moi mais 7min quoi). En sachant que là c'est ultra flagrant qu'il manque un move mais il y a plein de trucs dans la STL qui sont plus lents que juste écrire la même chose soi même, ce qui est dommage (même Lynix le dit que les std::unordered_map et autres std::set sont lent il me semble).

                          • Partager sur Facebook
                          • Partager sur Twitter
                            11 mai 2022 à 18:32:15

                            @JadeSalina, tes remarquent montrent que tu n'as malheureusement toujours pas compris comment fonctionnent "std::move" (vampirisme).

                            Les membres du comité de standardisation sont des imbéciles, bien sûr, mais eux, ils ont compris comment ça fonctionne, ces "imbécilités".

                            >Et les std::shared_ptr sont une implémentation d'un type de gestion mémoire qui s'appelle le reference counting

                            Où t'as vu qu'il n'y avait qu'une implémentation autorisée ? En plus c'est très facilement customisable;

                            Oui, les membres du comité de standardisation sont des imbéciles, mais qui a pu bien avoir cette idée saugrenue de customisation ? :waw:

                            @JadeSalina, t'as tout ce qu'il fait pour proposer une demande d'évolution du standard du C++, une boite mail, à toi de jouer pour que la STL soit plus rapide, GO !

                            • Partager sur Facebook
                            • Partager sur Twitter
                            Je recherche un CDI/CDD/mission freelance comme Architecte Logiciel/ Expert Technique sur technologies Microsoft.
                              11 mai 2022 à 18:42:16

                              bacelar a écrit:

                              @JadeSalina, tes remarquent montrent que tu n'as malheureusement toujours pas compris comment fonctionnent "std::move" (vampirisme).

                              Quelles remarques ? On doit mal se comprendre parce que je sais exactement comment fonctionne std::move ainsi que la sémantique de mouvement

                              bacelar a écrit:

                              Où t'as vu qu'il n'y avait qu'une implémentation autorisée ? En plus c'est très facilement customisable;

                              Ce que je veut dire c'est que ce que font les shared_ptr c'est du reference counting, qui est une façon parmi d'autres de gérer ses ressources, tout comme les exceptions sont une façon parmi d'autres de gérer les erreurs.

                              bacelar a écrit:

                              @JadeSalina, t'as tout ce qu'il fait pour proposer une demande d'évolution du standard du C++, une boite mail, à toi de jouer pour que la STL soit plus rapide, GO !


                              Malheureusement ce n'est pas possible, ce qu'il faut commencer par faire pour être plus rapide c'est être moins générique et plus spécialisé, mais ce n'est pas l'objectif de la STL. Et aussi j'ai oublié de le dire mais tous les compilateurs n'ont pas les mêmes implémentations standards, ce qui est également quelque chose à prendre en compte quand on veut s'assurer qu'on fait un truc qui tourne bien partout.

                              koala01 a écrit:

                              Si tu sais exactement ce que tu fais et que tu travailles avec une approche RAII cohérente, tu n'es bien sur pas impérativement tenu à utiliser std::unique_ptr ou std::shared_ptr.  Mais si tu as le moindre doute, cela restera quand même des "valeurs sures"

                              Ah voilà il y a bien d'autres façons de faire merci beaucoup de préciser ceci

                              -
                              Edité par JadeSalina 11 mai 2022 à 19:01:47

                              • Partager sur Facebook
                              • Partager sur Twitter
                                11 mai 2022 à 18:52:31

                                > J'espère que vous n'avez pas oublié un std::move quelque part, ce qui provoquerait une copie du std::shared_ptr et donc une non libération des ressources.

                                What? Si tu as ce genre de problématique, c'est que le shared_ptr est franchement mal employé. Sauf micro cas d'optim, la bestiole est faite pour être copiée.

                                Quant aux perfs, on sait très bien que cela ne vaut rien. C'était juste ce que l'on avait de mieux en C++98. Faut dire que les programmes qui vont vite... dans le mut, ça finit par lasser. Et dans le vrai monde du critique (avec vie humaine en jeu), on n'aime pas trop quand ça plante.

                                Accessoirement, quand la perf est critique, on évite les allocations à tout bout de champs. Ou du moins, on les localise hors du chemin à forte intensité calculatoire... Les vecteur de shared_ptr, gros bouaif aussi. shared_ptr c'est un peu la variable globale des pointeurs intelligents. Quand on peut, on va préférer savoir qui est responsable.

                                > Pourquoi avoir utilisé std::accumulate au lieu de faire un truc comme ça ?

                                Bonne question. J'aimerai bien savoir pourquoi il a utilisé accumulate pour un truc qui ressemble furieusement à un min_element.

                                A l'opposé il y a des gens qui vont plus vite avec accumulate: https://www.youtube.com/watch?v=PDSvjwJ2M80 Il faut dire que cela peut aider à virer des problèmes d'aliasing, de réévaluation idiote de borne de fin...

                                • Partager sur Facebook
                                • Partager sur Twitter
                                C++: Blog|FAQ C++ dvpz|FAQ fclc++|FAQ Comeau|FAQ C++lite|FAQ BS| Bons livres sur le C++| PS: Je ne réponds pas aux questions techniques par MP.
                                  11 mai 2022 à 19:08:40

                                  Arrêtez de croire Jade sur parole quand il parle d'une vidéo. Une fois sur 2, il comprend tout de travers et sort de leur contexte les choses pour leur faire dire ce qu'il veut.

                                  Pour rappel, l'API de std::accumulate (c'est à dire la partie qui est définie dans la norme par le comité de normalisation) n'a pas changé avec le C++20, c'est toujours un passage par valeur des paramètres. Parler d'un changement de std::accumulate avec le C++20 qui produirait un bug n'a aucun sens.

                                  Et surtout, dans la vidéo, accumulate est utilisé pour faire une recherche. L'élément trouvé est effectivement retourné par copie... puisque std::accumulate est censé changer cette valeur, il ne peut pas y avoir un move.

                                  Le code initial qui "bug" :

                                  Un exemple d'implémentation de std::accumulate dans clang Mac :

                                  accumulate(_InputIterator __first, _InputIterator __last, _Tp __init, _BinaryOperation __binary_op)
                                  {
                                      for (; __first != __last; ++__first)
                                          __init = __binary_op(__init, *__first);
                                      return __init;
                                  }
                                  

                                  Ca n'a aucun sens de faire un move ici.

                                  Alors que dans la vidéo, comme c'est une recherche, Cherno voudrait que la valeur retournée (un shared_ptr) ne soit pas copiée.

                                  Et le code final corrigé, c'est a dire sans utiliser std::accumulate, n'utilise pas de move, mais une référence sur l'élément du tableau.

                                  Bref, Jade dit du caca, comme d'habitude. Il déforme les informations qu'il voit. Et l'erreur de Cherno, c'est d'avoir utiliser std::accumulate pour faire autre chose que ce à quoi c'est destiné. (On voit que son code final est similaire a un std::find_if).

                                  -
                                  Edité par gbdivers 11 mai 2022 à 19:16:23

                                  • Partager sur Facebook
                                  • Partager sur Twitter
                                    11 mai 2022 à 19:23:07

                                    lmghs a écrit:

                                    A l'opposé il y a des gens qui vont plus vite avec accumulate: https://www.youtube.com/watch?v=PDSvjwJ2M80 Il faut dire que cela peut aider à virer des problèmes d'aliasing, de réévaluation idiote de borne de fin...


                                    C'est faux :) Les 2 bouts de code font exactement la même chose (https://godbolt.org/z/oW4xbz9dT). Donc les 3% plus rapide on se demande d'où ils sortent (il ne le montre pas de ce que j'en ai vu). En tant qu'humain, on voit qu'on fait un fill, un accumulate, etc, ok on est d'accord, mais le compilateur n'intègre pas du tout cette logique, tout ce qu'il voit c'est des appels de fonction qu'il va optimiser, exactement comme si c'était des fonctions qu'on avait écrit dans notre propre code (en plus simple souvent)

                                    Alors pour The Cherno lui il lit le code qu'un mec a écrit et il le corrige, ce n'est pas lui qui a eu l'idée du accumulate, et quand je parle du move dans le accumulate c'est pas au niveau de l'interface, c'est au niveau de l'appel de l'op dans la boucle dans l'implémentation, qui contient bien un std::move depuis C++20 (https://en.cppreference.com/w/cpp/algorithm/accumulate). Sinon bien sûr qu'on a évidemment pas du tout envie de move notre objet quand on le passe à std::accumulate wtf

                                    Et sinon oui ne me croyez pas allez voir les vidéos surtout celles de Casey ce sont les plus intéresssantes :D

                                    -
                                    Edité par JadeSalina 11 mai 2022 à 19:24:32

                                    • Partager sur Facebook
                                    • Partager sur Twitter
                                      11 mai 2022 à 19:29:40

                                      Le code donné dans cppreference est juste informatif. Il ne provient pas de la norme C++.

                                      Et le move qui a été ajouté pour les cas où l'opérateur binaire utilise des valeurs et pas des références, comme c'est le cas dans le code montré par Cherno. La perte de performance est la même, avec ou sans std::move.

                                      Donc non, le problème n'est pas ce move, le problème c'est d'utiliser std::accumulate pour faire autre chose que accumuler.

                                      Et que tu comprend (involontairement ? Je commence a douter) les choses de travers pour qu'elles aillent dans ton sens.

                                      -
                                      Edité par gbdivers 11 mai 2022 à 19:31:48

                                      • Partager sur Facebook
                                      • Partager sur Twitter
                                        11 mai 2022 à 19:30:25

                                        >On doit mal se comprendre parce que je sais exactement comment fonctionne std::move ainsi que la sémantique de mouvement

                                        Ok, alors peux-tu me donner un cas d'utilisation "lisite" de "std::shared_ptr + std::move" qui générerait des fuites mémoires par un "oubli" de l'utilisateur , STP ?

                                        C'est comme ça que j'ai interprété le premier paragraphe de ton post : des fuites mémoires.

                                        >Ce que je veut dire c'est que ce que font les shared_ptr c'est du reference counting

                                        J'ai compris ce que tu ne penses mais vérifies tes dire, rien n'empêche de faire autrement (garbage_collector, etc...) et ces imbéciles de standardisateurs ont permis de customiser l'implémentation :cf. les paramètres "Alloc" des constructeurs de "std::shared_ptr" (et les autre):

                                        https://en.cppreference.com/w/cpp/memory/shared_ptr/shared_ptr

                                        >Malheureusement ce n'est pas possible,

                                        Bin si, c'est possible, c'est tout le sens des paramètres "Alloca(tor)" des constructeurs de la STL.

                                        >mais ce n'est pas l'objectif de la STL

                                        Mais comment tu peux savoir ça quand tu ne sais même pas ce qu'elle offre concrètement ???

                                        >mais tous les compilateurs n'ont pas les mêmes implémentations standards

                                        C'est pas vraiment au niveau du compilateur mais de l'implémentation de la STL, il peut avoir plusieurs implémentations de le STL par compilateur.

                                        Et c'est CUSTOMISABLE, bordel.

                                        >Malheureusement ce n'est pas possible,

                                        Il y a déjà des allocateurs "alternatifs" dans la STL, pourquoi ta "super implémentation" ne pourrait pas faire partie du prochain standard (à moins que tu penses que l'imbécilité est contagieuse par e-mail ?)

                                        • Partager sur Facebook
                                        • Partager sur Twitter
                                        Je recherche un CDI/CDD/mission freelance comme Architecte Logiciel/ Expert Technique sur technologies Microsoft.
                                          11 mai 2022 à 20:47:22

                                          Eh merde.

                                          Comment nodiscard fonctionne ?

                                           passe a

                                          Defaut de conception de std::shared_ptr et std::move par les createurs du C++.

                                          @AbcAbc6 je veux fermer ce sujet 🏃🏼‍♂️🏃🏼‍♂️🏃🏼‍♂️🏃🏼‍♂️

                                          • Partager sur Facebook
                                          • Partager sur Twitter
                                            11 mai 2022 à 21:55:30

                                            Asmitta a écrit:

                                            Eh merde.

                                            Comment nodiscard fonctionne ?

                                             passe a

                                            Defaut de conception de std::shared_ptr et std::move par les createurs du C++.

                                            @AbcAbc6 je veux fermer ce sujet 🏃🏼‍♂️🏃🏼‍♂️🏃🏼‍♂️🏃🏼‍♂️

                                            Bienvenue sur OCR :)
                                            Et tu as tord de vouloir fermer le sujet, c'est très instructif pour ceux qui passent par là, comme moi ..

                                            -
                                            Edité par hugoducine 11 mai 2022 à 21:56:33

                                            • Partager sur Facebook
                                            • Partager sur Twitter
                                              11 mai 2022 à 22:10:22

                                              Moi je comprends les deux points de vue et je trouve cela bien qu'il y ait une diversité dans les "réguliers" du forum.

                                              Je comprends l'idée que la STL devient un peu obèse et entraine parfois des syntaxes affreuses pour faire des choses simples. Mais il y a des choses très sympa aussi. Par exemple en ce moment pour mes collisions j'utilise beaucoup la manipulation de bits. Jusqu'ici j'utilisais pas mal de techniques de bit hacks comme dans ce genre de bouquin. Mais je trouve finalement le header <bit> (c'est du c++20) bien plus efficace. Je gagne pas mal de perfs et de simplicité d'écriture par rapport aux solutions "faites-main" proposées ici ou .

                                              Après je comprends aussi le côté grisant de s'attaquer à des tâches bas-niveau, de s'abstraire des sur-couches et des solutions toutes faites, de se sentir plus libre et autonome. Je pense que Casey (que je ne connais pas) exalte la créativité, l'esprit d'indépendance et la motivation de ses followers. Cela est une bonne chose, même s'il y a peut-être une petite part illusoire et contre-productive là dedans.

                                              -
                                              Edité par Umbre37 11 mai 2022 à 22:23:41

                                              • Partager sur Facebook
                                              • Partager sur Twitter
                                                11 mai 2022 à 22:11:56

                                                bacelar a écrit:

                                                >On doit mal se comprendre parce que je sais exactement comment fonctionne std::move ainsi que la sémantique de mouvement

                                                Ok, alors peux-tu me donner un cas d'utilisation "lisite" de "std::shared_ptr + std::move" qui générerait des fuites mémoires par un "oubli" de l'utilisateur , STP ?

                                                C'est comme ça que j'ai interprété le premier paragraphe de ton post : des fuites mémoires.

                                                Oui c'est bien ce que j'ai dit, par exemple dans ce cas :

                                                class RessourceManager {
                                                public:
                                                  void add_ressource(std::shared_ptr<Ressource> ressource) {
                                                    ressources.push_back(std::move(ressource));
                                                  }
                                                
                                                private:
                                                  std::vector<std::shared_ptr<Ressource>> ressources;
                                                };
                                                
                                                std::shared_ptr<Ressource> load_ressource(std::filesystem::path path) {
                                                  return std::make_shared<Ressource>(path, ...);
                                                }
                                                
                                                
                                                // Quelque part dans le code
                                                auto my_ressource = load_ressource("fichier.txt");
                                                my_ressource->set_quelque_chose(...);
                                                
                                                get_manager().add_ressource(my_ressource); // OOOUUUPPS

                                                 (les ... c'est pas des parameter pack expansion c'est juste pour dire qu'on met quelque chose)

                                                Et désolé Asmitta à chaque fois ça part en cacahuète mais c'est pas du tout mon but, j'avais créé un sujet dédié pour une fois mais ça a dégénéré dans celui là aussi :(



                                                -
                                                Edité par JadeSalina 11 mai 2022 à 22:15:14

                                                • Partager sur Facebook
                                                • Partager sur Twitter
                                                  11 mai 2022 à 22:16:46

                                                  Asmitta a écrit:

                                                  Plus je lis tes reponses plus je me rends compte qu'il va falloir que je devienne assez fort en francais pour pouvoir partager mes -maigres- connaissances a d'autres.

                                                  Non, tu ne dois pas me prendre comme exemple à ce niveau ;)

                                                  Dis toi que les personnes ne sont jamais que la somme de leur vécu, et qu'après un demi siècle d'un parcours tout à fait atypique, ben j'ai un vécu particulier "qui fait que" ...

                                                  Qui fait principalement que je suis un gars très sérieux qui refuse de se prendre au sérieux.  Et qui explique que j'aime mettre une touche d'humour dans mes explications à  chaque fois qu'il est possible de le faire ;)

                                                  Et comme, en plus, j'ai la prétention de maîtriser quand même un tout petit peu mon sujet, ben, j'en rajoute un peu selon l'éternel principe que "la culture, c'est comme la confiture" :D

                                                  Tout cela pour dire que tu ne dois  pas forcément essayer de copier mon style.  Tu trouveras tôt ou tard le tien, en fonction de ton propre vécu. Ce qui est largement plus intéressant, par contre, c'est de maitriser ton sujet.  Le reste, ca viendra "naturellement" ;)

                                                  Ceci dit, cela fait toujours plaisir de lire quelqu'un trouve mes explications claires :D, merci pour le compliment  ;)

                                                  JadeSalina a écrit:

                                                  koala01 a écrit:

                                                  Si tu sais exactement ce que tu fais et que tu travailles avec une approche RAII cohérente, tu n'es bien sur pas impérativement tenu à utiliser std::unique_ptr ou std::shared_ptr.  Mais si tu as le moindre doute, cela restera quand même des "valeurs sures"

                                                  Ah voilà il y a bien d'autres façons de faire merci beaucoup de préciser ceci

                                                  Décidément, tu  as l'art de réduire tout un paragraphe à la seule partie qui semble aller dans ton sens, quitte à  dénaturer l'ensemble de ce qui est dit.

                                                  Bien sur, il y a parfaitement moyen de fournir ses propres capsules RAII, et je ne renierai pas ce que j'ai écrit plus haut: ce n'est même pas forcément si difficile que cela.

                                                  Seulement, tu oublie les parties essentielles de ce paragraphe:

                                                  • à condition de savoir ce que l'on fait (et mieux encorepourquoi on le fait)
                                                  • et dans le doute, les outils fournis par la bibliothèques standard restent des valeurs sures, des solutions qui t'évitent de te perdre dans un tas de détails dont tu n'as au final sans doute rien à foutre.

                                                  Alors, bien sur que l'on peut le faire.  De toutes manières, c'est ton code, c'est toi qui l'organise comme tu le veux.  C'est exactement comme pour le goto dont j'ai parlé.

                                                  Seulement fait gaffe, parce que le jour où tu m'aura comme lead technique sur un projet, si je peux accepter "certaines libertés" à différents niveaux, il faudra quand même que le code que tu écris respecte mes règles, et que je ne me gênerai absolument pas pour supprimer un commit -- dut il porter sur de nombreux fichiers et résoudre bon nombre de problèmes -- s'il n'y a ne serait-ce qu'une ligne de code qui a l'heure de ne pas me plaire.

                                                  Car oui, ca, c'est la prérogative du leader technique ;)

                                                  • Partager sur Facebook
                                                  • Partager sur Twitter
                                                  Ce qui se conçoit bien s'énonce clairement. Et les mots pour le dire viennent aisément.Mon nouveau livre : Coder efficacement - Bonnes pratiques et erreurs  à éviter (en C++)Avant de faire ce que tu ne pourras défaire, penses à tout ce que tu ne pourras plus faire une fois que tu l'auras fait
                                                    11 mai 2022 à 22:56:10

                                                    JadeSalina a écrit:

                                                    Oui c'est bien ce que j'ai dit, par exemple dans ce cas :

                                                    Aucune fuite mémoire dans cet exemple. Il y a une copie évitable du shared_ptr et un move serait mieux (voire un unique_ptr en fait), on est d'accord la dessus. Mais my_ressource sera détruit à la fin de la fonction et il n'y aura aucun problème de mémoire.

                                                    -
                                                    Edité par gbdivers 11 mai 2022 à 22:59:49

                                                    • Partager sur Facebook
                                                    • Partager sur Twitter
                                                      13 mai 2022 à 2:55:56

                                                      JadeSalina a écrit:

                                                      Et désolé Asmitta à chaque fois ça part en cacahuète mais c'est pas du tout mon but, j'avais créé un sujet dédié pour une fois mais ça a dégénéré dans celui là aussi :(

                                                      Mais, au moins, sur ton propre sujet, ce sont tes cacahuètes à toi, avec, même si tu ne les supporte pas, des réflexion et de réponses sur ton point de vue, et sans risquer d'emm...der la personne qui a posé la question d'origine et qui voit son sujet prendre une direction tout autre.
                                                      • Partager sur Facebook
                                                      • Partager sur Twitter
                                                      Ce qui se conçoit bien s'énonce clairement. Et les mots pour le dire viennent aisément.Mon nouveau livre : Coder efficacement - Bonnes pratiques et erreurs  à éviter (en C++)Avant de faire ce que tu ne pourras défaire, penses à tout ce que tu ne pourras plus faire une fois que tu l'auras fait

                                                      Comment nodiscard fonctionne ?

                                                      × 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