Partage
  • Partager sur Facebook
  • Partager sur Twitter

création d'un objet temporaire ... ou pas ?

C++

    17 mars 2019 à 21:57:51

    Bonsoir,

    j'ai voulu tester un code simple afin de voir ce qu'il se passe (appel de constructeur, opérateur d'affectation par déplacement).

    Lorsque j'appelle la fonction suivante

    template<typename T>
    void setName(T&& newName)
    {
    name = std::forward<T>(newName);
    }

    name

    est une donnée membre de type std::string d'une classe à laquelle la fonction template précédente appartient.

    D'après mes tests, si je fais, avec a une instance de la classe :

    a.setname("openclassromms");

    il y a création d'un objet temporaire au moment de l'appel de la fonction setName puis appel de l'opérateur d'affectation par déplacement.

    Or en principe, le littéral "openclassrooms" devrait être passé directement à name sans création d'un objet temporaire.

    Est-ce que le résultat que j'ai en runtime, est normal ?

    Je vous remercie par avance



    -
    Edité par YES, man 17 mars 2019 à 23:37:19

    • Partager sur Facebook
    • Partager sur Twitter
      17 mars 2019 à 23:01:16

      YES, man a écrit:

      Lorsque j'appelle la fonction suivante

      Ton code n'est pas valide.

      YES, man a écrit:

      il y a création d'un objet temporaire au moment de l'appel de la fonction setName puis appel de l'opérateur d'affectation par déplacement.

      Tu as montré par le passé que tu avais des problèmes pour mettre en pratique ce que tu apprends.

      Donnes le code complet qui montre cela.

      YES, man a écrit:

      Or en principe, le littéral "openclassrooms" devrait être passé directement à name sans création d'un objet temporaire.

      Ca veut rien dire. Détailes ce que tu penses qui devrait arriver (quels objets construits ? quand ? quels fonctios appélées ?)

      • Partager sur Facebook
      • Partager sur Twitter
      Pour poser des questions ou simplement discuter informatique, vous pouvez rejoindre le discord NaN.
        17 mars 2019 à 23:15:16

        Merci. Et le reste de mes remarques ?

        Question subsidiaire : pourquoi tu utilises std::forward ici ?

        • Partager sur Facebook
        • Partager sur Twitter
        Pour poser des questions ou simplement discuter informatique, vous pouvez rejoindre le discord NaN.
          17 mars 2019 à 23:34:00

          std::forward, seems valid pour du Perfect Forwading (Move au lieu de Copy)

          Oui c'est logique, tu passe d'un String Literal à un std::string, donc création d'un objet std::string.
          Ensuite l'objet membre "name" utilise le constructeur par déplacement de l'objet précédemment créé.

          Ce qu'il faut savoir c'est qu'avec les templates c'est le même principe que les fonction inline. Au final le compilateur peut optimiser grandement le tout, beaucoup plus bas niveau.
          Tu peux considérer le résultat en version optimisé, comme s'il n'y avait pas de création d'objet temporaire.
          • Partager sur Facebook
          • Partager sur Twitter
          CWC, pour compiler facilement du C++. CW un nouveau langage intuitif. GZE - Un moteur C++/Cw
            17 mars 2019 à 23:36:50

            Bonsoir Maeiky,

            dans mon cas, j'ai vérifié qu'à l'exécution, lorsque l'on utilise la fonction template au-dessus, il y a pourtant création d'un objet temporaire.

            • Partager sur Facebook
            • Partager sur Twitter
              18 mars 2019 à 0:31:09

              Oui, c'est ce que je dis ;)
              C'est normal car tu passe d'un String Literal à un std::string, si tu passe directement un
              std::string, il n'y aura pas d'objet temporaire.
              • Partager sur Facebook
              • Partager sur Twitter
              CWC, pour compiler facilement du C++. CW un nouveau langage intuitif. GZE - Un moteur C++/Cw
                18 mars 2019 à 2:02:31

                Quand tu écris

                "

                Oui c'est logique, tu passe d'un String Literal à un std::string, donc création d'un objet std::string
                Ensuite l'objet membre "name" utilise le constructeur par déplacement de l'objet précédemment créé.

                "

                J'ai un doute :

                je dirais plutôt que c'est d'abord un constructeur par déplacement qui est utilisé pour créer un objet temporaire std::string.

                Puis l'opérateur d'affectation par déplacement.

                Qu'en penses-tu ?

                • Partager sur Facebook
                • Partager sur Twitter
                  18 mars 2019 à 2:53:22

                  YES, man a écrit:

                  je dirais plutôt que c'est d'abord un constructeur par déplacement qui est utilisé pour créer un objet temporaire std::string.

                  Est-ce que le constructeur par mouvement prend en parametre un char* ?
                  • Partager sur Facebook
                  • Partager sur Twitter
                  Pour poser des questions ou simplement discuter informatique, vous pouvez rejoindre le discord NaN.
                    18 mars 2019 à 3:00:43

                    YES, man a écrit:

                    je dirais plutôt que c'est d'abord un constructeur par déplacement qui est utilisé pour créer un objet temporaire std::string.


                    Qu'est ce qui te fait penser cela?

                    Voici ce que je pense :
                    http://www.cplusplus.com/reference/string/string/string/

                    Ce qui nous intéresse, parmi les constructeur:
                    string (const char* s);
                    string (string&& str) noexcept;

                    a.setname("openclassromms");
                    "openclassromms" est un String Literal, T est un std::string
                    void setName(T&& newName)
                    On ne peut passer directement une référence, on doit appeler le constructeur: string (const char* s);
                    D'où l'objet temporaire, ensuite il est passé par référence sur Rvalue &&

                    Après:
                    name = std::forward<T>(newName);
                    Un peu comme le ferait std::Move, il va appeler le constructeur par déplacement : string (string&& str) noexcept;

                    Mais bon, c'est le genre de micro optimisation qui ne serait pas nécessaire si std::string suivrait le principe de COW (Copy On Write), ou bien tout autre objet qui utilise le compte de références.

                    • Partager sur Facebook
                    • Partager sur Twitter
                    CWC, pour compiler facilement du C++. CW un nouveau langage intuitif. GZE - Un moteur C++/Cw
                      18 mars 2019 à 17:03:59

                      > "openclassromms" est un String Literal, T est un std::string

                      T est un char const(&)[15]. Les templates ne font jamais de transformation de type et cela n'aurait aucun sens avec le perfect forwarding.

                      > On ne peut passer directement une référence

                      Si, c'est le principe des références universelles. https://zestedesavoir.com/tutoriels/474/la-deduction-de-type-en-c/

                      > Mais bon, c'est le genre de micro optimisation qui ne serait pas nécessaire si std::string suivrait le principe de COW (Copy On Write), ou bien tout autre objet qui utilise le compte de références.

                      C'est la grosse merde le COW sur std::string, ce n'est pas pour rien que les implémentations l'ont supprimé (et aussi parce que la norme l'empêche, mais c'est un détail). Le COW oblige des conditions et une copie pour chaque fonction susceptible de modifier la chaîne, y comprit la version non const de operator[], ce qui arrive très vide. Le COW cause aussi des problèmes avec les itérateurs qui peuvent référencer le mauvais objet suite à un appel de operator[].

                      -
                      Edité par jo_link_noir 18 mars 2019 à 17:04:34

                      • Partager sur Facebook
                      • Partager sur Twitter
                        18 mars 2019 à 18:08:32

                        jo_link_noir a écrit:

                        > "openclassromms" est un String Literal, T est un std::string

                        T est un char const(&)[15]. Les templates ne font jamais de transformation de type et cela n'aurait aucun sens avec le perfect forwarding.


                        Oui, ça plus de sens >_<

                        Mais, j'ai l'impression que ça change rien car il n'y a pas de constructeur par déplacement pour un String Literal dans std::string?

                        jo_link_noir a écrit:

                        C'est la grosse merde le COW sur std::string, ce n'est pas pour rien que les implémentations l'ont supprimé (et aussi parce que la norme l'empêche, mais c'est un détail). Le COW oblige des conditions et une copie pour chaque fonction susceptible de modifier la chaîne, y comprit la version non const de operator[], ce qui arrive très vide. Le COW cause aussi des problèmes avec les itérateurs qui peuvent référencer le mauvais objet suite à un appel de operator[].

                        Je crois que tu fais une misconception du principe COW, car s' il y a qu'une instance (dans la plupart des cas) il n'y aura pas de copie.

                        Aussi, en terme de performances tu peux avoir plus d'optimisations, si tu prend le cas ci-dessus, std::string doit faire une copie de la chaine pour permettre l'écriture, dans le cas du COW, il n'y a pas besoin de copier la chaine, tant qu'elle est utilisé en lecture.

                        Tu peux aussi séparer les accès lectures/écritures, ce qui au final ne fait pas plus de condition qu'un std::string en lecture

                        -
                        Edité par Maeiky 18 mars 2019 à 19:46:07

                        • Partager sur Facebook
                        • Partager sur Twitter
                        CWC, pour compiler facilement du C++. CW un nouveau langage intuitif. GZE - Un moteur C++/Cw
                          18 mars 2019 à 20:03:04

                          >Aussi, en terme de performances tu peux avoir plus d'optimisations,

                          Si c'est les performances, on oublie aussi le COW pour utiliser des trucs fait exprès.

                          https://en.cppreference.com/w/cpp/string/basic_string_view

                          • Partager sur Facebook
                          • Partager sur Twitter
                          Je recherche un CDI/CDD/mission freelance comme Architecte Logiciel/ Expert Technique sur technologies Microsoft.
                            18 mars 2019 à 21:55:47

                            bacelar a écrit:

                            Si c'est les performances, on oublie aussi le COW pour utiliser des trucs fait exprès.

                            https://en.cppreference.com/w/cpp/string/basic_string_view


                            Sans trop être hors sujet, personnellement je ne considère pas ça comme une solution, ce n'est simplement pas générique.
                            Vous êtes vite sur la gâchette pour tout jeter à la poubelle, j'ai à peine évoquer une partie des possibilités.

                            Pour avoir fait ma propre implémentation, il est possible de faire des références de sous string, dans ce cas par exemple, un appel de substr ce fait sans même de copie (donc gratuit), ce qui est beaucoup plus intéressant en terme de performances.

                            Après c'est à vous de voir, je voulais simplement dire que le principe du move ne s'applique pas à tout.
                            • Partager sur Facebook
                            • Partager sur Twitter
                            CWC, pour compiler facilement du C++. CW un nouveau langage intuitif. GZE - Un moteur C++/Cw
                              18 mars 2019 à 22:25:25

                              Maeiky a écrit:

                              Mais, j'ai l'impression que ça change rien car il n'y a pas de constructeur par déplacement pour un String Literal dans std::string?

                              Par définition, un constructeur par mouvement prend le même type, donc of course qu'il n'y a pas un tel constructeur, sinon ca ne serait pas un constructeur par mouvement.

                              Maeiky a écrit:

                              Je crois que tu fais une misconception du principe COW

                              [...]

                              Vous êtes vite sur la gâchette pour tout jeter à la poubelle, j'ai à peine évoquer une partie des possibilités. 

                              Non, tu n'as pas compris les arguments de joe_link_noir (qui ne sont d'ailleurs pas de lui, ce sont des problèmes connus du COW). On n'a pas besoin de toi pour nous expliquer les avantages et défauts du COW, c'est un pattern qui est utilisé depuis des dizaines d'années et qui est bien connu.

                              C'est une solution qui est utilisé dans Qt par exemple et ils ont fait ce choix en parfaite connaissance des problèmes. (Qt n'est pas critique sur ce point en termes de performances, c'est pour cela qu'ils ont fait ce choix). Au contraire, la lib standard est critique sur les performances ("on ne paie pas pour ce qu'on utilise pas") et ils ont donc fait un choix différents.

                              Libre a toi de faire tes propres choix sur tes projets, mais c'est bof bof de critiquer le choix fait sur d'autres projets (la lib standard) sans connaitre les tenants et aboutissants de chaque projet.

                              Maeiky a écrit:

                              Pour avoir fait ma propre implémentation, il est possible de faire des références de sous string, dans ce cas par exemple, un appel de substr ce fait sans même de copie (donc gratuit), ce qui est beaucoup plus intéressant en terme de performances.

                              Donc en gros, tu as implémenté std::string_view...

                              Encore une fois, libre a toi de faire les choix que tu veux sur tes propres projets. Mais à moins que tu as trouvé une implémentation super génial qui peut gérer dynamiquement 2 systèmes d'ownership différents dans la même classe (RAII pour std::string, pas d'ownership pour string_view) sans surcout, ton implémentation n'est pas acceptable pour la lib standard.

                              Maeiky a écrit:

                              ce n'est simplement pas générique.

                              Tu as une conception limitée de la généricité. Effectivement, std::string_view n'est pas une classe polymorphique, qu'on va pouvoir utiliser partout et qui va tout gérer en interne de façon transparente. Mais ça, c'est de la conception à la Java, cela a un coût.

                              std::string_view est au contraire extrêmement générique, puisque cela permet créer des views sur n'importe quel type de chaînes (char*, std::string, QString, etc), voire sur des types qui ne sont pas des chaînes a la base (simplement en fournissant les spé template adéquates).

                              Je crois que tu devrais prendre un peu de recul. Si des centaines de devs expert en C++ et des comités de normalisation on fait un choix, il y a des raisons derrière.

                              -
                              Edité par gbdivers 18 mars 2019 à 22:30:52

                              • Partager sur Facebook
                              • Partager sur Twitter
                              Pour poser des questions ou simplement discuter informatique, vous pouvez rejoindre le discord NaN.
                                18 mars 2019 à 23:21:11

                                Ce sont de bon points, je ne voulais pas critiquer l’approche standard, qui est tout aussi bonne.
                                • Partager sur Facebook
                                • Partager sur Twitter
                                CWC, pour compiler facilement du C++. CW un nouveau langage intuitif. GZE - Un moteur C++/Cw
                                  19 mars 2019 à 0:09:52

                                  > Mais, j'ai l'impression que ça change rien car il n'y a pas de constructeur par déplacement pour un String Literal dans std::string?

                                  Il y a les versions avec char* qui ne font pas d'objet intermédiaire. Mais comme dit @gbdivers, un constructeur de déplacement prend le même type que la classe.

                                  > dans le cas du COW, il n'y a pas besoin de copier la chaine, tant qu'elle est utilisé en lecture.

                                  C'est sûr ce point qu'il y a un problème. Pour garantir la lecture seule, il ne faut utiliser que des fonctions constantes. Or, la plupart des fonctions membres de std::string on 2 versions et manipuler une chaîne non constante est très facile, même dans le cas d'une lecture seule.

                                  std::string s;
                                  std::getline(std::cin, s);
                                  for (char c : s) { // oups, std::string::begin/end doit faire une copie (itérateur non const)
                                  }
                                  
                                  if (s[0]) { // oups, operator[] retourne un char& => ce n'est pas une lecture seule
                                  }

                                  Il n'y aura pas toujours la copie, mais le COW oblige tout de même à vérifier que le compteur de référence soit à 1. Condition très coûteuse dans un parcours. D'ailleurs, Qt recommande l'usage de qconst ou autres mécanisme similaire pour éliminer ce genre de test.

                                  Autres problèmes du COW: le multithreading. Et comme je disais plus haut, des problèmes avec les itérateurs comme ce fut le cas avec libstdc++ dans certaines conditions.

                                  std::string s1 = "plop";
                                  std::string s2 = s1;
                                  
                                  auto it = std::as_const(s2).begin();
                                  s2[0] = 'A';
                                  // *it != s2[0]
                                  

                                  => https://wandbox.org/permlink/79WULj4FwfmCbFj8

                                  Actuellement, les implémentations font du SSO (Short String Optimization). C'est aussi le cas de std::function. Je crois que les implémentations de libc++ et libstdc++ permettent d'avoir 8 caractères avant de faire une allocation dynamique et l'implémentation de facebook (folly::string) jusqu'à 15.

                                  Le COW est utile dans certaines circonstances, mais il pose aussi pas mal de problème. Je trouve que le seul moment où il passe bien, c'est avec des objets qui fournissent une unique fonction pour accéder aux données non-const. Même s'il y a toujours le problème des références invalides comme pour l'exemple au-dessus.

                                  -
                                  Edité par jo_link_noir 19 mars 2019 à 0:11:56

                                  • Partager sur Facebook
                                  • Partager sur Twitter
                                    19 mars 2019 à 4:00:11

                                    jo_link_noir a écrit:

                                    std::string s1 = "plop";
                                    std::string s2 = s1;
                                    
                                    auto it = std::as_const(s2).begin();
                                    s2[0] = 'A';
                                    // *it != s2[0]
                                    

                                    Même s'il y a toujours le problème des références invalides comme pour l'exemple au-dessus.


                                    Est-ce que c'est un problème ou c'est le résultat attendu? Ta référence est valide car tu ne veux surtout pas modifier une constante. C'est exactement le but recherché du COW.

                                    Je vois 2 scénarios possibles:
                                    #1 Tu considère que modifier l'élément même qui se fait itérer est une mauvaise pratique, dans ce cas le COW crée une copie de l'objet en cas de modification, donc c'est bien le résultat voulu comme le démontre ton exemple et c'est encore plus safe.

                                    #2 Tu autorise la modification, tu fais un itérateur custom qui utilise l'index au lieu d'un pointeur et le tour est joué.

                                    jo_link_noir a écrit:

                                    Autres problèmes du COW: le multithreading.

                                    En quoi?
                                    J'aurais pensé le contraire. Tu peux facilement avoir une ressource string partagé entre plusieurs threads. Si un de ceux-ci la modifier. Il en créer automatiquement une copie, il en devient en quelque sorte propriétaire. Il faut seulement avoir la variable du compte par référence en atomic.

                                    jo_link_noir a écrit:

                                    C'est sûr ce point qu'il y a un problème. Pour garantir la lecture seule, il ne faut utiliser que des fonctions constantes. Or, la plupart des fonctions membres de std::string on 2 versions et manipuler


                                    Tu suggère de faire une surcouche à std::string, qui ne serait sans doute pas optimal je te l'accorde. Mais je parle plutôt du principe lui même, après tu l'implémente comme tu veux.
                                    • Partager sur Facebook
                                    • Partager sur Twitter
                                    CWC, pour compiler facilement du C++. CW un nouveau langage intuitif. GZE - Un moteur C++/Cw
                                      19 mars 2019 à 6:18:34

                                      Maeiky a écrit:

                                      jo_link_noir a écrit:

                                      Autres problèmes du COW: le multithreading.

                                      En quoi?
                                      J'aurais pensé le contraire. Tu peux facilement avoir une ressource string partagé entre plusieurs threads. Si un de ceux-ci la modifier. Il en créer automatiquement une copie, il en devient en quelque sorte propriétaire. Il faut seulement avoir la variable du compte par référence en atomic.

                                      Payer des atomic à chaque modification d'une string ?!

                                      -
                                      Edité par Ksass`Peuk 19 mars 2019 à 6:23:25

                                      • Partager sur Facebook
                                      • Partager sur Twitter
                                      Posez vos questions ou discutez informatique, sur le Discord NaN | Tuto : Preuve de programmes C
                                        19 mars 2019 à 12:36:58

                                        Oui, je reste un peu mitiger là dessus, je préfère séparer complètement les données entre thread.
                                        Mais sinon ça reste pas pire qu'un shared_ptr qui utilise les atomic à fond.

                                        En théorie ça reste le même coût qu'une variable normal, mais je soupçonne que le compilo ne peut appliquer certaines optimisations?
                                        • Partager sur Facebook
                                        • Partager sur Twitter
                                        CWC, pour compiler facilement du C++. CW un nouveau langage intuitif. GZE - Un moteur C++/Cw
                                          19 mars 2019 à 13:16:37

                                          Maeiky a écrit:

                                          Oui, je reste un peu mitiger là dessus, je préfère séparer complètement les données entre thread.
                                          Mais sinon ça reste pas pire qu'un shared_ptr qui utilise les atomic à fond.

                                          Ben façon de dire hein. std::shared_ptr, tu paies un accès atomique seulement quand tu copies le pointeur, ce qui est censé être rare. Là :

                                          for(char& c : my_string){
                                            c = '0' ;
                                          }

                                          Tu fais littéralement my_string.size() opération atomiques.

                                          Maeiky a écrit:

                                          (1) En théorie ça reste le même coût qu'une variable normal, (2) mais je soupçonne que le compilo ne peut appliquer certaines optimisations?

                                          (1) Non, selon l'opération le coût varie. Au minimum, à supposer que les opérations en mode read/acquire soient suffisantes (je ne suis pas convaincu du tout, il faudrait faire une preuve), sur x86 c'est le même coût, en ARM c'est plus cher (largement). Si tu as besoin de consistance séquentielle (ce qui me semble plus probable), là même sur x86, tu paies un mfence qui flush des caches dans tous les sens et verrouille des choses pendant l'opération.

                                          (2) Plein, en fait (see: "Common Compiler Optimization are Invalid under C11 Memory Model").

                                          -
                                          Edité par Ksass`Peuk 19 mars 2019 à 13:17:40

                                          • Partager sur Facebook
                                          • Partager sur Twitter
                                          Posez vos questions ou discutez informatique, sur le Discord NaN | Tuto : Preuve de programmes C
                                            19 mars 2019 à 13:48:14

                                            J'ai refait quelques tests et en fait , non,

                                            1) je constate que lorsque l'on passe un literal à setName, en tant que fonction template, il n'y a pas création d'objet temporaire au moment du passage de l'argument dans la fonction template.

                                            Par contre, il semble qu'il y ait création d'un objet temporaire par l'opérateur d'affectation par déplacement , ce qui peut se comprendre étant donné que ce n'est pas une fonction template.

                                            2) Par contre , si je fais :

                                            void setName(T&& newName)
                                            {
                                            name = std::move(newName);
                                            }

                                            il y a création d'un objet temporaire au tout début.

                                            Par contre, l'assignation par déplacement ne créé pas d'objet temporaire. Pourquoi pas dans ce cas ?

                                            Donc comment se fait-il que dans le cas de la fonction template

                                            template<typename T>
                                            void setName(T&& newName)
                                            {
                                            name = std::forward<T>(newName);
                                            }



                                            , il y a création d'un objet temporaire précisément au moment de l'affectation par déplacement (je veux dire au moment du passage de l'argument à  l'opérateur d'affectation par déplacement) alors que ça n'est pas vrai dans le cas de la surcharge lorsque l'on fait un passage par une Rvalue Reference ?

                                            *****

                                            Mon hypothèse qui me semble la plus plausible, c'est :

                                            l'opérateur d'affectation par déplacement est défini en paramètre avec une référence rvalue, donc dans le cas d'une fonction template, le literal  string étant transmis tel quel à l'opérateur d'affectation par déplacement, il est donc converti à ce moment-là seulement.

                                            Par contre dans le cas de la surcharge avec une référence rvalue, le temporaire est déjà créé, donc c'est un string Rlvalue (utilisation de std::move) qui est transmis à l'opérateur d'affectation par déplacement. Donc pas besoin d'en recréer un dans ce cas

                                            *******

                                            Par avance merci

                                            -
                                            Edité par YES, man 19 mars 2019 à 14:11:30

                                            • Partager sur Facebook
                                            • Partager sur Twitter
                                              19 mars 2019 à 16:20:48

                                              YES, man a écrit:

                                              1) je constate

                                              Montre comment tu fais tes constations.

                                              Tout ce que tu dis part de constations fausses. Et donc tu comprends n'importe quoi

                                              • Partager sur Facebook
                                              • Partager sur Twitter
                                              Pour poser des questions ou simplement discuter informatique, vous pouvez rejoindre le discord NaN.
                                                19 mars 2019 à 18:37:39

                                                @YES, man

                                                Je pense que tu as bien compris, en résumé:

                                                #include <iostream>
                                                using namespace std;
                                                
                                                std::string name;
                                                
                                                void setname(std::string newName)  
                                                {
                                                    name = std::forward<std::string>(newName); //--> use:  "string (string&& str)"
                                                }
                                                int main(){
                                                	setname("openclassromms"); //--> use: "string (const char* s)"
                                                }
                                                #include <iostream>
                                                using namespace std;
                                                
                                                std::string name;
                                                
                                                void setname(const char* const& newName)
                                                {
                                                    name = std::forward<const char* const&>(newName); //--> use: string (const char* s), then, string (string&& str)
                                                }
                                                int main(){
                                                	setname("openclassromms");
                                                }


                                                @Ksass`Peuk

                                                J'aimerais avoir ton avis sur ce qu'il y a derrière std::string:

                                                // _Rep: string representation
                                                      //   Invariants:
                                                      //   1. String really contains _M_length + 1 characters: due to 21.3.4
                                                      //      must be kept null-terminated.
                                                      //   2. _M_capacity >= _M_length
                                                      //      Allocated memory is always (_M_capacity + 1) * sizeof(_CharT).
                                                      //   3. _M_refcount has three states:
                                                      //      -1: leaked, one reference, no ref-copies allowed, non-const.
                                                      //       0: one reference, non-const.
                                                      //     n>0: n + 1 references, operations require a lock, const.
                                                      //   4. All fields==0 is an empty string, given the extra storage
                                                      //      beyond-the-end for a null terminator; thus, the shared
                                                      //      empty string representation needs no constructor.
                                                
                                                      struct _Rep_base
                                                      {
                                                    size_type        _M_length;
                                                    size_type        _M_capacity;
                                                    _Atomic_word        _M_refcount;
                                                      };
                                                /**
                                                   *  @brief  Subscript access to the data contained in the %string.
                                                   *  @param  __pos  The index of the character to access.
                                                   *  @return  Read/write reference to the character.
                                                   *
                                                   *  This operator allows for easy, array-style, data access.
                                                   *  Note that data access with this operator is unchecked and
                                                   *  out_of_range lookups are not defined. (For checked lookups
                                                   *  see at().)  Unshares the string.
                                                   */
                                                  reference
                                                  operator[](size_type __pos)
                                                  {
                                                    // Allow pos == size() both in C++98 mode, as v3 extension,
                                                // and in C++11 mode.
                                                _GLIBCXX_DEBUG_ASSERT(__pos <= size());
                                                    // In pedantic mode be strict in C++98 mode.
                                                _GLIBCXX_DEBUG_PEDASSERT(__cplusplus >= 201103L || __pos < size());
                                                _M_leak();
                                                    return _M_data()[__pos];
                                                  }
                                                void
                                                _M_leak()    // for use in begin() & non-const op[]
                                                {
                                                if (!_M_rep()->_M_is_leaked())
                                                _M_leak_hard();
                                                }
                                                
                                                bool _M_is_leaked() const _GLIBCXX_NOEXCEPT
                                                { return this->_M_refcount < 0; }
                                                • Partager sur Facebook
                                                • Partager sur Twitter
                                                CWC, pour compiler facilement du C++. CW un nouveau langage intuitif. GZE - Un moteur C++/Cw
                                                  19 mars 2019 à 18:56:19

                                                  Maeiky a écrit:

                                                  @Ksass`Peuk

                                                  J'aimerais avoir ton avis sur ce qu'il y a derrière std::string:

                                                  Du code de C++03, c'est écrit quelques lignes avant :

                                                  _GLIBCXX_END_NAMESPACE_CXX11
                                                  #else  // !_GLIBCXX_USE_CXX11_ABI
                                                    // Reference-counted COW string implentation
                                                  • Partager sur Facebook
                                                  • Partager sur Twitter
                                                  Posez vos questions ou discutez informatique, sur le Discord NaN | Tuto : Preuve de programmes C
                                                    19 mars 2019 à 19:10:16

                                                    Maeiky a écrit:

                                                    @YES, man

                                                    Je pense que tu as bien compris, en résumé:

                                                    #include <iostream>
                                                    using namespace std;
                                                    
                                                    std::string name;
                                                    
                                                    void setname(std::string newName)  
                                                    {
                                                        name = std::forward<std::string>(newName); //--> use:  "string (string&& str)"
                                                    }
                                                    int main(){
                                                    	setname("openclassromms"); //--> use: "string (const char* s)"
                                                    }
                                                    #include <iostream>
                                                    using namespace std;
                                                    
                                                    std::string name;
                                                    
                                                    void setname(const char* const& newName)
                                                    {
                                                        name = std::forward<const char* const&>(newName); //--> use: string (const char* s), then, string (string&& str)
                                                    }
                                                    int main(){
                                                    	setname("openclassromms");
                                                    }

                                                    Stop les hypothèses hasardeuses sans savoir comment il constate ce qu'il constate. 

                                                    Et dans tous les cas :

                                                    1. c'est pas le constructeur par mouvement mais l'opérateur d'affectation par mouvement

                                                    2. il y a forcement un appel au constructeur std::string(char*) et un appel a l'opérateur d'affectation par mouvement dans les 2 sytnaxes.

                                                    Et je repose ma question : pourquoi std::forward ici ?

                                                    -
                                                    Edité par gbdivers 19 mars 2019 à 19:12:45

                                                    • Partager sur Facebook
                                                    • Partager sur Twitter
                                                    Pour poser des questions ou simplement discuter informatique, vous pouvez rejoindre le discord NaN.
                                                      19 mars 2019 à 20:01:52

                                                      Ksass`Peuk a écrit:

                                                      Du code de C++03, c'est écrit quelques lignes avant :

                                                      _GLIBCXX_END_NAMESPACE_CXX11
                                                      #else  // !_GLIBCXX_USE_CXX11_ABI
                                                        // Reference-counted COW string implentation

                                                      Pas dans toute les implémentations:
                                                      Même le commentaire veux tout dire:
                                                      // Allow pos == size() both in C++98 mode, as v3 extension,
                                                      // and in C++11 mode.
                                                      // and in C++11 mode.
                                                      _GLIBCXX_DEBUG_ASSERT(__pos <= size());
                                                          // In pedantic mode be strict in C++98 mode.
                                                      _GLIBCXX_DEBUG_PEDASSERT(__cplusplus >= 201103L || __pos < size());
                                                      _M_leak();
                                                          return _M_data()[__pos];
                                                        }

                                                      Mais bon, je voulais mentionner que ça déjà été fait et que personne ne semble avoir vue la différence :p
                                                      Sinon merci pour les explications.

                                                      -
                                                      Edité par Maeiky 19 mars 2019 à 20:18:03

                                                      • Partager sur Facebook
                                                      • Partager sur Twitter
                                                      CWC, pour compiler facilement du C++. CW un nouveau langage intuitif. GZE - Un moteur C++/Cw
                                                        19 mars 2019 à 21:22:20

                                                        Le commentaire parle de l'assertion qui n'a aucun putain de rapport avec le COW, qui lui est interdit en C++11 comme la mentionné jo_link_noir il y a déjà un bail ...

                                                        • Partager sur Facebook
                                                        • Partager sur Twitter
                                                        Posez vos questions ou discutez informatique, sur le Discord NaN | Tuto : Preuve de programmes C
                                                          19 mars 2019 à 21:40:41

                                                          Je sais c'est pas ça que je voulais que tu regarde, j'imagine qu'il y a eu transition
                                                          https://stackoverflow.com/questions/24826936/c11-internal-stdstring-representation-libstdc

                                                          Il ne l'on pas enlevé pour cause de perf...
                                                          https://stackoverflow.com/questions/12199710/legality-of-cow-stdstring-implementation-in-c11

                                                          • Partager sur Facebook
                                                          • Partager sur Twitter
                                                          CWC, pour compiler facilement du C++. CW un nouveau langage intuitif. GZE - Un moteur C++/Cw
                                                            19 mars 2019 à 21:44:15

                                                            > #1 Tu considère que modifier l'élément même qui se fait itérer est une mauvaise pratique, dans ce cas le COW crée une copie de l'objet en cas de modification, donc c'est bien le résultat voulu comme le démontre ton exemple et c'est encore plus safe.

                                                            Juste comme ça, le const_iterator n'empêche pas la modification de la chaîne. Dans mon exemple, il faut comprendre que l'itérateur de s2 pointe sur les données de s1. Donc modifier s1[0] change la valeur de l'itérateur. On a vu mieux pour le côté safe.

                                                            • Partager sur Facebook
                                                            • Partager sur Twitter

                                                            création d'un objet temporaire ... ou pas ?

                                                            × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
                                                            • Editeur
                                                            • Markdown