IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C++ Discussion :

probleme de const et cache


Sujet :

C++

  1. #1
    Membre confirmé Avatar de themadmax
    Profil pro
    Inscrit en
    Juillet 2005
    Messages
    446
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2005
    Messages : 446
    Points : 496
    Points
    496
    Par défaut probleme de const et cache
    Bonjour,

    J'ai un petit problème, j'ai des accesseurs qui mettent à jour des membres de ma classe si celle-ci n'est pas encore initialisé. Le problème c'est que je ne peux déclaré ces accesseur comme const, et que cela ce répercute sur tout le reste de mon programme. Avez-vous une astuce pour ce genre de problème ?

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    class Toto
    {
       string _name ;
       bool _init;
       const string& getName() /* j'aimerai mettre const */
       { 
          if(!_init) init(); //fonction non const
          return _name ;
       }
       void init() { _name = "operation longue"; _init = true; } //fonction non const
    }
    Merci d'avance
    ________________________________________________
    http://bliquid.fr : Blog sur Android et l'Acer Liquid

  2. #2
    Rédacteur/Modérateur
    Avatar de JolyLoic
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    5 463
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 5 463
    Points : 16 213
    Points
    16 213
    Par défaut
    Déclares tes variables de ce type mutable
    Ma session aux Microsoft TechDays 2013 : Développer en natif avec C++11.
    Celle des Microsoft TechDays 2014 : Bonnes pratiques pour apprivoiser le C++11 avec Visual C++
    Et celle des Microsoft TechDays 2015 : Visual C++ 2015 : voyage à la découverte d'un nouveau monde
    Je donne des formations au C++ en entreprise, n'hésitez pas à me contacter.

  3. #3
    Membre éclairé
    Avatar de Ekleog
    Homme Profil pro
    Étudiant
    Inscrit en
    Janvier 2012
    Messages
    448
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Janvier 2012
    Messages : 448
    Points : 879
    Points
    879
    Par défaut
    Au passage, pourquoi ne pas initialiser dans le constructeur ?

  4. #4
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 614
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 614
    Points : 30 626
    Points
    30 626
    Par défaut
    Salut,

    En effet, il serait sans doute préférable d'utiliser le constructeur ( après tout, il sert à ca, non ), ce qui donnerait quelque chose comme
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    class Toto
    {
        public:
            Toto():name_("operation longue"){}
            Toto(std::string const & name):name_(name){}
            std::string const & name() const{return name_;}
        private:
            std::string name_;
    };
    Tu n'aurais ainsi meme plus à t'inquiéter de savoir si l'objet est effectivement initialisé, ce qui ne peut qu'etre bénéfique

    En outre, en travaillant de la manière que tu présente, tu risques d'avoir un effet de bord pour le moins désagréable:

    Si tu rajoutes n'importe quelle fonction qui teste ou modifie le membre name_ à ta classe, le résultat sera différent en fonction du fait que l'utilisateur aura (ou non) déjà invoqué la fonction name() (ou la fonction init() ) , ce qui retire toute chance de prédicabilité du résultat:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
     
    class Toto
    {
        public:
            bool isCorrect() const
            {
                return name_=="test";
            }
            std::string const & name() const
            {
                if(!initialized_)
                    init();
                return name_;
            }
            void init()
            {
                name_="test";
                initialized_ = true;
            }
        private:
            bool initialized_;
            std::string name_;
    };
    int main()
    {
        Toto t;
        std::cout<< t.isCorrect(); // sortie : 0 (false)
        t.name();
        sttd::cout<<t.isCorrect(); // sortie : 1 (true) on n'a pourtant pas invoqué
                                   // sciemment init !!!
        Toto t2;
        t2.init(); //que doit on faire, appeler init, ou name ???
        return 0;
    }
    Ceci dit, le mot clé mutable présente l'énorme inconvénient de supprimer tout controle de constance sur le membre défini mutable

    Une solution, qui, de plus, a l'avantage d'attirer l'attention du lecteur de code sur le fait que l'on décide de manière réfléchie et limitée de passer outre de la constance de l'objet peut etre le recours au const_cast:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    class Holder
    {
        /* juste pour la facilité d'écriture ;) */
        typedef std::vector<Type> vector;
        public:
            typedef typename vector::const_iterator const_iterator;
            Holder():needToBeSorted_(false),items_(){}
            /* les fonctions qui vont réellement modifier l'objet */
            void add(Type const &  toadd) 
            {
                items_.push_back(toadd);
                needToBeSorted_ = true;
            }
            /* une fonction qui ne modifie pas forcément l'état de l'objet */
            const_iterator find(DataType const & value) const
            {
                const_cast<Holder &>(*this).sort();
                const_iterator it;
                /* rechercher l'élément en question */
                return it;
            }
        private:
            void sort()
            {
                 if(needToBeSorted_)
                     std::sort(items_.begin(),items_.end());
                  needToBeSorted_ = false;
            }
            bool needToBeSorted_;
            vector items_;
    };
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  5. #5
    Rédacteur/Modérateur
    Avatar de JolyLoic
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    5 463
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 5 463
    Points : 16 213
    Points
    16 213
    Par défaut
    Franchement, je n'aime pas ta proposition à base de const_cast, et lui préfère largement mutable.

    Déjà, mutable, il suffit de lire la déclaration de la classe pour savoir qu'une donnée membre est spéciale, et que la constance logique de la classe ne dépendra pas de la constance de cette donnée membre. Je pense important de savoir le rôle de cette donnée dès sa déclaration. C'est une information sur le design de la classe, pas un détail d'implémentation. Quand on lit bool needToBeSorted_;, on ne sait pas trop le rôle de cette variable. Si on lit mutable bool needToBeSorted_;, on sait tout de suite que la classe va implémenter un mécanisme de cache d'information, et que cette variable va avoir un rôle clef dans le mécanisme.

    En contraste, avec const_cast, il faut lire l'ensemble des implémentations des fonctions pour comprendre le rôle de cette variable.

    Ensuite, ton exemple avec const_cast n'est pas légal
    En effet, const_cast ne permet pas de modifier un objet constant (un tel objet pourrait avoir été écrit dans de la mémoire non modifiable). Il permet juste deux choses :
    - De faire taire le système de type quand on doit passer une valeur constante à un fonction qui n'a pas déclaré qu'elle ne la modifiera pas, mais qui en pratique ne la modifiera pas. Très pratique pour s'interfacer avec du vieux code C.
    - Quand on a une variable que l'on sait être modifiable, mais qu'on n'y a accès que par un chemin où cette information a été perdue. Comme un int auquel on n'a accès que par un int const *.
    Pour plus de détails, lire le §7.1.6.1 (en particulier l'exemple paragraphe 5).
    Ma session aux Microsoft TechDays 2013 : Développer en natif avec C++11.
    Celle des Microsoft TechDays 2014 : Bonnes pratiques pour apprivoiser le C++11 avec Visual C++
    Et celle des Microsoft TechDays 2015 : Visual C++ 2015 : voyage à la découverte d'un nouveau monde
    Je donne des formations au C++ en entreprise, n'hésitez pas à me contacter.

  6. #6
    Rédacteur/Modérateur
    Avatar de JolyLoic
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    5 463
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 5 463
    Points : 16 213
    Points
    16 213
    Par défaut
    Citation Envoyé par Ekleog Voir le message
    Au passage, pourquoi ne pas initialiser dans le constructeur ?
    Citation Envoyé par koala01 Voir le message
    En effet, il serait sans doute préférable d'utiliser le constructeur ( après tout, il sert à ca, non ), ce qui donnerait quelque chose comme
    [...]
    Tu n'aurais ainsi meme plus à t'inquiéter de savoir si l'objet est effectivement initialisé, ce qui ne peut qu'etre bénéfique
    En règle générale, je suis d'accord avec vous deux. Il y a pourtant parfois des cas où cette règle générale ne s'applique pas, en particulier quand cette initialisation est très coûteuse, et que dans un grand nombre de cas, elle ne sera pas utilisée.

    Il peut être alors intéressant de mettre en place un mécanisme "lazy" qui fera uniquement l'initialisation dans les rares cas où elle est requise.
    Ma session aux Microsoft TechDays 2013 : Développer en natif avec C++11.
    Celle des Microsoft TechDays 2014 : Bonnes pratiques pour apprivoiser le C++11 avec Visual C++
    Et celle des Microsoft TechDays 2015 : Visual C++ 2015 : voyage à la découverte d'un nouveau monde
    Je donne des formations au C++ en entreprise, n'hésitez pas à me contacter.

  7. #7
    Membre confirmé Avatar de themadmax
    Profil pro
    Inscrit en
    Juillet 2005
    Messages
    446
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2005
    Messages : 446
    Points : 496
    Points
    496
    Par défaut
    Citation Envoyé par Ekleog Voir le message
    Au passage, pourquoi ne pas initialiser dans le constructeur ?
    En effet, dans le cas général il faudrait initialisé le contenu dans le constructeur mais l’opération d’initialisation est assez couteuse en temps et surtout elle n'est pas demander à chaque fois mon objet peut être créer sans jamais avoir d'appel à la fonction getName().
    Il me semble que la solution mutable semble convenir à mon problème.

    @koala01 il est vrai qu'il ne faut jamais passé par le membre directement, mais utilisé l’accesseur qu'il lui correspond. Pour la class Holder je la garde de coté...

    Merci pour vos réponses précises
    ________________________________________________
    http://bliquid.fr : Blog sur Android et l'Acer Liquid

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. probleme avec les dossier caché
    Par beusedogg dans le forum Windows 7
    Réponses: 3
    Dernier message: 17/07/2011, 18h18
  2. [eZ Publish] probleme avec les noeuds cachés
    Par dev-deb dans le forum EDI, CMS, Outils, Scripts et API
    Réponses: 2
    Dernier message: 19/05/2011, 14h33
  3. Probleme utilisation const void*
    Par mansgueg dans le forum C++
    Réponses: 5
    Dernier message: 07/03/2011, 20h39
  4. probleme de "const correctness"
    Par GuiYom00 dans le forum C
    Réponses: 2
    Dernier message: 13/10/2008, 14h21
  5. Probleme de mise en cache
    Par TRUNKS-SSJ7 dans le forum Balisage (X)HTML et validation W3C
    Réponses: 5
    Dernier message: 25/03/2007, 20h08

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo