Partage
  • Partager sur Facebook
  • Partager sur Twitter

Cast de const en non-const qui recopie

std::vector

    6 août 2008 à 16:12:24

    Salut !

    J'ai fait un petit test récemment, et je voudrais discuter du résultat.
    voici mon petit code :

    #include <vector>
    
    std::vector<int> fonc()
    {
    	std::vector<int> res;
    	res.push_back(53);
    	res.push_back(37);
    	return res;
    }
    
    int main()
    {
    	const std::vector<int> V = fonc();
            //V.clear();
    	((std::vector<int>)V).clear();
    	size_t a = V.size();
    	return 0;
    }
    


    ma fonction fonc construit un vector de 2 elements et le retourne.
    Je recupere ça dans le main, dans un const vector (je le verouille en écriture).

    2e ligne (commentée) je fais V.clear() -> ça ne compile pas. Normal, clear n'est pas une méthode const (normal), donc ça ne compile pas. Jusque la je suis d'accord. Je commente cette ligne

    3e ligne, je cast sauvagement le const vector en vector -> déprotection par le cast. Avant de compiler, je m'étais parié que ça ne compilerais pas !! Qu'il me dirait "cannot convert const to non-const"
    et ben non !!!! Il compile !!
    La je hurle, je me dis "on peut facilement faire péter les mécanismes de protection".
    Je lance le clear, ça compile.

    Heureusement, 4e ligne, je teste la size : V n'a pas été touché. clear n'a "pas marché".
    Je pousse un soupir de soulagement : "non, on ne peut pas faire péter les mécanismes de protection si facilement"

    Et la, je trace en debug. Qu'a fait clear ?
    Je constate que le cast de V en vector non const a appelé le constructeur de recopie. Il a donc été créée une variable temporaire, copie de V, et cette variable a subie le clear...

    Maintenant, ma question : pourquoi ce cast C-style a t il appelé le constructeur de recopie ?
    Est ce que tout cast C-style appelle des constructeurs par recopie ??
    Qu'en est il de static_cast ?

    Quels sont les mécanismes sousjascents mis en jeu ?
    • Partager sur Facebook
    • Partager sur Twitter

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

      6 août 2008 à 16:25:02

      (Je ne mis connais pas beaucoup, ce que je dis peut être faux)

      - C'est peut-être à cause de ce genre de cas qu'il faut utiliser les cast C++
      - Pour ce genre de cast il y a const_cast<> (à proscrire)
      • Partager sur Facebook
      • Partager sur Twitter
        6 août 2008 à 16:35:36

        Il me semble que c'est parce que
        (std::vector<int>)V).clear();
        
        est equivalent à
        std::vector<int>(V).clear();
        
        • Partager sur Facebook
        • Partager sur Twitter
          6 août 2008 à 17:24:29

          Un cast "à la C" est un cast très sauvage. Le compilateur fait alors entièrement confiance au programmeur.

          Plus d'informations sur les casts C++:
          http://h-deb.clg.qc.ca/Sujets/Divers-- [...] asts-ISO.html
          • Partager sur Facebook
          • Partager sur Twitter
            6 août 2008 à 18:03:49

            Lors d'un cast, tu crèes de toute façon TOUJOURS une nouvelle variable, le plus souvent temporaire comme ici.

            Tu ne peux pas modifier la nature intrinsèque d'un objet, mais tu peux créer une nouvelle variable (objet) qui reprend tout ou partie du contenu de la 1ère en faisant un cast.

            const_cast crèe une nouvelle variable non constante.
            static_cast fait un cast "à la C".
            dynamic_cast transforme un pointeur sur mère en fille (entre autre).
            reinterpret_cast transforme les données brutes en autre chose.

            Mais tu créeras dans tous les cas une nouvelle variable.
            • Partager sur Facebook
            • Partager sur Twitter
            Co-auteur du cours de C++. ||| Posez vos questions sur le forum ||| Me contacter.
              6 août 2008 à 18:31:39

              const_cast ne crée pas de nouvelle variable, il essaie (!) de donner une vue modifiable sur une donnée qui officiellement ne l'est pas.

              Suivant le contexte, et des subtilités vicieuses [*], un cast à la C peut résulter en un des 3 casts qui n'est pas un reinterpret_cast.

              Maintenant, est-ce qu'il est normal que le (T)kv (avec kv de type "T const") se comporte comme un T(kv), j'avoue ne mettre jamais posé la question. [Je dirais que c'est le genre de trucs à vérifier dans la norme ou sur fclc++]

              [*] Un cast C sur un pointeur entre types dont on n'a qu'une déclaration (anticipée) va provoquer un reinterpret_cast au lieu d'un static_cast.

              EDIT: plein de choses dans la FAQ comeau que j'ai la flemme de relire.
              • 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.
                6 août 2008 à 18:41:53

                Pour le const_cast, cela crée bien une nouvelle variable (ou plutot pointeur en fait) non ?

                const double pi = 3.14;
                  const double* p_pi = &pi;
                
                  double* a = const_cast<double*>(p_pi);
                


                le pointeur a est bien une nouvelle variable et p_pi est toujours non-modifiable.
                • Partager sur Facebook
                • Partager sur Twitter
                Co-auteur du cours de C++. ||| Posez vos questions sur le forum ||| Me contacter.
                  6 août 2008 à 18:51:06

                  Leur valeur est la même. Et je ne vois pas (enfin, je ne suis pas allé fouiller dans la norme pour ça) ce qui empêcherait le compilo de leur donner la même adresse tant que dans la portée concernée ils continuent tous les deux de pointer sur la même donnée.

                  Maintenant, c'est vrai que l'expression de l'OP est (T)kv et non (T&)kv ... hum ... elle viendrait de là la copie ?
                  • 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.
                    6 août 2008 à 20:28:40

                    Ca m'étonnerait quand même que la copie ne se fasse qu'au moment de la modification de la variable non-const.
                    • Partager sur Facebook
                    • Partager sur Twitter
                    Co-auteur du cours de C++. ||| Posez vos questions sur le forum ||| Me contacter.
                      6 août 2008 à 20:59:56

                      Si le compilo peut voir que sur toute leur portée les deux pointeurs sont sensés pointer sur la même adresse. AMA, il n'est pas obliger de définir une vraie nouvelle variable (pointeur) sur la pile. Pourquoi ne pourrait-il pas considérer l'autre pointeur comme un simple alias (à l'image des références).

                      La notion de const n'étant de toutes façon qu'un garde barrière vérifié au moment de la compilation. Après, le code machine final n'en sait plus rien.
                      • 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.
                        6 août 2008 à 21:13:28

                        Un constructeur n'ayant qu'un seul paramètre peut agir comme un operateur de conversion, implicite par défaut, explicite si spécifié. Comme il n'existe pas d'opérateur de conv de const en non-const pour vector, le compilo se sert du constructeur qui accepte un const vector en param, donc le constructeur par copie.

                        class T1 {
                        public:
                        	T1() {}
                        	T1(const T1 &) {}
                        };
                        
                        class T2 {
                        public:
                        	T2() {};
                        	T2(const T1 &) {}
                        	T2(const T2 &) {}
                        };
                        
                        class T3 : T2 {
                        public:
                        	
                        	T3() {}
                        	explicit T3(const T2 &) {}
                        
                        	operator T1 & () {return *((T1*)(this));}
                        };
                        
                        
                        void main() {	
                        
                        	T1 t1;
                        	T2 t2;
                        	T3 t3;
                        
                        	t2 = t1; // Appel du CTor de T2
                        	//t3 = t2; // ne compile pas car CTor de T3 explicit
                        	t3 = T3(t1); // conversion implicite de t1 en T2
                        	t1 = (T1)t3; // Appel du CTor par copie de T1 avec conv de t3 en T1
                        }
                        


                        En espérant que ça aide :)
                        • Partager sur Facebook
                        • Partager sur Twitter
                          6 août 2008 à 22:21:50

                          Avant tout merci pour vos réponses.
                          Si Spaz a raison, ceci expliquerait cela. Bien entendu, j'aimerais en etre sur, mais je ne vois pas d'autres explications.

                          Avant de marquer le sujet comme résolu, si quelqu'un a un lien vers une regle officielle la dessus, je suis preneur.

                          J'ai quand meme essayé la chose suivante par la suite (me disant que ça venait du cast C-style :

                          ((static_cast<std::vector<int> >(V)).clear();
                          


                          Et il se trouve que je tombe sur le meme résultat : le compilo passe, la fonction clear n'affecte pas V, mais visiblement une copie faite a la volée, dont l'existance n'est que temporaire dans cette ligne.

                          Avec ce "piege" comme quoi un bete cast pourrait entrainer une recopie, j'ai soudain comme un doute sur par mal de projets que j'ai fait (perso ET professionnels) en me disant que peut etre que je fais parfois des recopies non voulues et inutiles sans le savoir...
                          Bah... si c'est le cas, et que j'en trouve des occurrence, les clients seront content des prochaines versions qui iront plus vite... (si la différence se perçoit...)

                          Merci a vous tous !

                          Si vous avez la preuve quelque part sur un lien officiel que le cast peut recopier, je suis preneur, et ce sera la résolution du topic !
                          • Partager sur Facebook
                          • Partager sur Twitter

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

                          Cast de const en non-const qui recopie

                          × 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