Partage
  • Partager sur Facebook
  • Partager sur Twitter

utilisation de std::string dans un constructor

Sujet résolu
    19 mai 2019 à 10:09:15

    Bonjour, et merci d’avance si vous pouvez m’aider,

    J’essaie de ne plus utiliser les tableaux de caractères à la mode C, et de les remplacer par des std::string. J’ai besoin dans une classe d’un constructeur avec une string qui pourrait avoir une valeur par défaut. J’ai fait plusieurs essais de syntaxe, mais j’ai pas trouvé.

     
    #include <iostream>
    #include <string>
    
    using namespace std::string_literals;
    
    class TTmp {
    private:
        std::string m_name;
    public:
        TTmp (std::string & name = ""s); // erreur
    // TTmp (std::string & name = &""s); // erreur
    // TTmp (std::string & name = std::string {""s}); // erreur
    // TTmp (std::string name = ""s); // <- OK pas d'erreur!
    };
    
    TTmp::TTmp (std::string & name) : m_name {name}
    //TTmp::TTmp (std::string name) : m_name {name}
    {
    }
    
    int main()
    {
       TTmp first {"cool"s};
       return 0;
    }

    Message d’erreur :

    .../main.cpp:10:32: error: cannot bind non-const lvalue reference of type ‘std::__cxx11::string& {aka std::__cxx11::basic_string<char>&}’ to an rvalue of type ‘std::__cxx11::basic_string<char>’

    Dans mes différents essais, le dernier test (passage de la variable [avec une valeur par defaut] par valeur) compile, mais, je pense que ce n’est pas correcte de passer une string par valeur.

    (Je ne sais pas où chercher : je n’ai rien trouver dans le cours de Zeste de savoir ou de Quillaume et quand à cppreference.com ou http://www.cplusplus.com/ je ne trouve pas la page qui va bien.)

    J’ai continué mes tests :

    #include <iostream>
    #include <string>
    
    using namespace std::string_literals;
    
    class TTmp {
    private:
        std::string m_name;
    public:
        TTmp (std::string & name);
    };
    
    TTmp::TTmp (std::string & name) : m_name {name}
    {
    }
    
    int main()
    {
       TTmp first {""s};
       std::string sec{""s};
       TTmp second {sec};
       return 0;
    }
    « first » ne compile pas (même erreur), mais « second » lui compile !

    Je ne comprend pas ! (Il y a des lacunes dans mon ignorance !) Est ce que vous pourrez m’expliquez ? Merci d’avance !

    Cordialement.

    • Partager sur Facebook
    • Partager sur Twitter
      19 mai 2019 à 10:56:30

      Hello,

      Sais-tu à quoi sert l'esperluette "&" dans la signature d'une fonction ? Tous tes soucis viennent de là :).

      • Partager sur Facebook
      • Partager sur Twitter

      ...

        19 mai 2019 à 12:51:32

        Salut,

        Et, si tu tiens à l'esperluette, quelle est la condition sine qua non qui permette de créer une variable temporaire anonyme qui pourra servir "d'objet référencé" le temps de l'exécution de la fonction?

        -
        Edité par koala01 19 mai 2019 à 12:52:05

        • 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
          19 mai 2019 à 14:20:49

          Merci GuitOXx pour cette réponse rapide.

          le '&' (esperluette, je ne connaissais pas le nom, c'est joli !), indique que ce n'est pas une variable, mais. sa référence. En cherchant à nouveau dans ce sens, je suis arrivé à la conclusion que l'on ne peut pas prendre la référence d'un littéral, et ""s reste un littéral (même avec un s à la fin), ce n'est pas une constante. J'ai modifier le code comme ça, et ca marche! - "eurêka!"

          #include <iostream>
          #include <string>
          
          using namespace std::string_literals;
          
          const std::string vide {""s};
          
          class TTmp {
          private:
              std::string m_name;
          public:
              TTmp (const std::string & name = vide);
          };
          
          TTmp::TTmp (const std::string & name) : m_name {name}
          {
          }
          
          int main()
          {
             TTmp first {"cool"s};
             return 0;
          }
          

          Est-ce bien ça que tu voulais me faire découvrir, GuitOXx ?

          Merci Koala01.

          Je viens juste de finir de taper ma réponse à GuitOXx, et je trouves cette seconde réponse. Pour le "&" (tient vous avez le même nom  :)), c'est pas moi qui y tient, c'est la pile! Si on passe une string par valeur, ça va prendre beaucoup de temps et de place dans la pile, une référence c'est plus rapide et moins gourmand. Non, j'ai tord ?

          La solution que j'ai trouvé, c'est d'utilisé une constante globale, et donc de passer sa référence en valeur par défaut. J'aurais peut-être pu faire une constante statique dans l'objet, mais je ne crois pas que ça serve à quelque chose. (Tient, il faut que je regarde dans <string> s'il y a une string vide en constante ?)

          Là encore, c'est ce que tu voulais me faire dire, Koala01 ?

          Bien cordialement

          Editer à 17H30:

          Tout faut! je viens de reprendre, et le code ci-dessous compile:

          #include <iostream>
          #include <string>
          
          using namespace std::string_literals;
          
          class TTmp {
          private:
              std::string m_name;
          public:
              TTmp (const std::string & name = ""s);
              void set (const std::string & name = ""s);
          };
          
          TTmp::TTmp (const std::string & name) : m_name {name}
          {
          }
          
          void TTmp::set (const std::string & name)
          {
              m_name = name;
          }
          int main()
          {
             TTmp first {"cool"s};
             first.set();
             return 0;
          }
          

          Il me manquait des "const" dans les prototypes du constructor ! Donc contrairement à ce que j'étais arrivé comme conclusion, ""s est peut bien être pris en référence, mais c'est une référence "const std::string &" et pas "std::string &".
          c'est ce que tu voulais me faire dire, GuitOXx et Koala01 ?

          Bien cordialement.

          -
          Edité par Dedeun 19 mai 2019 à 17:42:39

          • Partager sur Facebook
          • Partager sur Twitter
            19 mai 2019 à 23:11:49

            Exactement...

            Quand tu travailles avec une référence (de manière générale), il faut impérativement que l'objet référencé existe au moment où l'on déclare la référence.

            Sauf si on a affaire à une référence constante (et que la référence sert de paramètre à une fonction, bien sur).  Dans ce cas, il  peut y avoir création d'un "variable temporaire anonyme":

            // imaginons une fonction dont le prototype est
            void foo(std::string const & temp)
            
            /* on peut faire appel à cette fonction sous la forme de */
            int main(){
                foo("Salut");
                /* qui provoque la création d'une "variable temporaire
                 * anonyme", de type std::string et dont la valeur est "Salut"
                 * qui n'existe que le temps que durera l'exécution de foo:
                 * C'est une variable temporaire, parce que sa durée de vie
                 * est limitée au temps d'exécution de foo
                 * C'est une variable anonyme car il n'existe absolument
                 * aucun identifiant permettant de la désigner (en dehors
                 * de la durée de l'exécution de foo
                 */
            }

            Ce n'est autorisé que parce que le compilateur est en mesure de s'assurer que la "variable référencée" ne sera jamais modifiée, du fait de la déclaration en tant que constante.

            En effet, le propre d'une référence (non constante) est de permettre au modifications apportées dans une fonction d'être répercutées au niveau de la donnée référencée au niveau de la fonction appelante.

            Or, comme il n'y a absolument aucun moyen de récupérer la donnée en question (vu qu'il s'agit d'une variable anonyme) et que, de plus, cette variable n'existera plus une fois que l'exécution de la fonction s'achève (vu que c'est une variable temporaire), il n'y a absolument aucune raison de permettre ... que cette variable soit modifiée ;). 

            Le fait de ne permettre qu'aux références constantes de provoquer la création d'une variable temporaire anonyme offre une possibilité supplémentaire au développeur, tout en s'assurant qu'il ne sera pas surpris de ne pas être en mesure de retrouver la variable qui aurait été modifée par mégarde ;)


            Mais ca, bien sur, c'était avant C++11...  Car, depuis lors, on dispose également de la sémantique de déplacement, et de toutes les notions qui y sont liées, comme celle des R value References ;)

            -
            Edité par koala01 19 mai 2019 à 23:12:12

            • 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
              20 mai 2019 à 18:23:25

              Merci Messieurs.

              koala01 a écrit:

              ...

              Mais ca, bien sur, c'était avant C++11...  Car, depuis lors, on dispose également de la sémantique de déplacement, et de toutes les notions qui y sont liées, comme celle des R value References ;)

              Bon, pas encore au niveau, on regardera ça plus tard (et je n'hésiterai pas à vous questionner).

              Bien Cordialement

              • Partager sur Facebook
              • Partager sur Twitter

              utilisation de std::string dans un constructor

              × 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