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

Langage C++ Discussion :

const correctness et retour de variable membre par référence


Sujet :

Langage C++

  1. #1
    r0d
    r0d est déconnecté
    Membre expérimenté

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    4 288
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Août 2004
    Messages : 4 288
    Billets dans le blog
    2
    Par défaut const correctness et retour de variable membre par référence
    Bonjour.
    Prenons le code suivant (ce code est inutile et faux, il sert juste à illustrer le problème existentiel qui m'habite):
    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
    class Foo
    {
    private:
       Element void_element;
       map< string, Element > container;
     
    public:
       Element & FindElement( const string & element_name, bool & found ) 
       { 
          auto element = container.find( element_name );
          if ( element == container.end() )
          {
             // on a pas trouvé l'élément recherché
             found = false;
             return void_element;
          }
          else
          {
             // on l'a trouvé
             found = true;
             return *it;
          }
       }
    };
    La fonction Foo::FindElement doit trouver un élément en fonction de son nom (ce nom est la clé de la map Foo::container). S'il le trouve, il renvoie une référence sur cet élément, sinon il renvoie un référence vers un objet bidon Foo::void_element. Le parametre found de la fonction détermine si l'élément a été trouvé ou non.

    Mon problème est le suivant: Cette fonction FindElement ne modifie pas la classe Foo, et elle n'est pas sensée le faire. Donc en toute logique, elle devrait être const. Seulement, si on déclare cette fonction comme constante, alors la référence qu'elle renvoie devra aussi être constante. Et c'est ça que je ne comprend pas. La philosophie de la constance d'une fonction est que cette fonction ne modifie pas l'état de la classe, mais pourquoi donc sommes-nous obligé de retourner une référence constante lorsque l'objet retourné est membre la classe? Comment fait-on si, par exemple, l'appelant veut pouvoir modifier l'élément renvoyé par cette fonction?

  2. #2
    Membre émérite

    Profil pro
    Inscrit en
    Décembre 2008
    Messages
    533
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2008
    Messages : 533
    Par défaut
    Sachant que const se propage, il est normal que les attributs d'un objet constant soient eux aussi constants. Et puisque implicitement, tu essaies de faire une conversion de <const Element&> vers <Element&>, il est normal que le compilo gueule. Sinon, il faut mettre tes attributs en mutable.

    Je trouve même plutôt rassurant que les cv-qualifiers se propagent y compris dans les pointeurs/références générés par l'objet.

  3. #3
    r0d
    r0d est déconnecté
    Membre expérimenté

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    4 288
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Août 2004
    Messages : 4 288
    Billets dans le blog
    2
    Par défaut
    Mais je ne comprend pas la logique.
    Il est normal et évident qu'une fonction membre const ne puisse appeler que des fonctions membres const. En revanche, je ne comprend pas la philosophie de la propagation au type de retour. Puisque l'idée de la constance d'une fonction membre est que cette dernière ne puisse pas modifier l'état de l'instance correspondante (lire ceci par exemple), quel est le rapport avec le type de retour? Et qu'est-ce que cela apporte? Je veux dire, si ton c'est ton type de retour que tu ne veux pas modifier, alors c'est le type de retour qui faut déclarer comme const, mais ça n'a rien à voir avec la constance de la fonction elle-même. Non?

  4. #4
    Membre émérite

    Profil pro
    Inscrit en
    Décembre 2008
    Messages
    533
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2008
    Messages : 533
    Par défaut
    Si on garde à l'esprit que :

    1. Une fonction membre const n'est rien d'autre qu'une fonction dont l'argument caché this est de type const Foo* const au lieu de Foo* const.
    2. La constance d'un objet se propage à ses sous-objets.
    3. Le cast d'une référence (ou un pointeur) non-constante vers son équivalent constant est permis, mais l'inverse non.


    Il n'y a rien d'illogique dans le fait qu'un type const Element d'un attribut issu de this ne puisse jamais être casté en Element&.

    Tu peux d'ailleurs très bien renvoyer une copie qui soit non-constante, à partir du moment où cette opération de recopie ne va pas à l'encontre du qualifier const que tu as toi-même affecté à this.

  5. #5
    Membre Expert

    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Août 2004
    Messages
    1 391
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 34
    Localisation : France, Doubs (Franche Comté)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 1 391
    Par défaut
    Bonjour,

    Imaginons que j'utilise ta classe Foo ainsi (et que le "const" ne se propage pas) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    void bar(const Foo& foo)
    {
      Element& e = foo.FindElement("a",true);
      e=Element();
    }
    En tant qu'appelant de la classe bar, je m'attend à ce que la valeur sémantique de foo avant et après l'appel soit la même (ie que les propriétés de foo avant et après soit les mêmes), or si le "const" ne se propage pas, alors ce n'est pas le cas.

    Deux solutions si la valeur de l'attribut n'a pas de sens sémantique, AMA :
    • Mutable, qui sert exactement à ca. Raison pour laquelle mutable est adapté à un compteur de référence intrusif dans les classes RAII-sante à responsabilité partagée.
    • Si l'objet n'est pas responsable de l'attribut (via référence ou pointeur par exemple), alors il n'y a pas de problème.

  6. #6
    Expert éminent
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 635
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 635
    Par défaut
    Salut,

    Le fait est que, lorsqu'un des membres de ta classe est une collections, on se base sur le principe que toute modification des éléments de la dite collection occasionnera une modification de l'état interne de la classe.

    A partir de là, il est "normal" si l'on décide de faire en sorte qu'une fonction constante renvoie une référence vers un objet (fusse-t-il un élément de la collection membre), de faire en sorte que cette référence ne puisse simplement pas être modifiée (et qu'elle soit donc elle aussi déclarée constante).

    De plus, comme Cob l'a si bien fait remarquer, le fait de déclarer une fonction membre comme constante indique au compilateur qu'il doit considérer que l'objet courent (ce qui est pointé par this) est un objet constant.

    A partir de là, il est tout à fait logique que tous les membres de l'objet courent qui ne sont pas déclarés explicitement mutable soient considérés comme étant eux-même constants.

    La suite n'est donc plus que la répétition de cette logique: ta collection étant constante, toute fonction renvoyant un itérateur renverra d'office un const_iterator, et donc, qui contiendra, dans le cas de find, une paire constante, ce qui fera que si la clé est (toujours) constante, la valeur le devient fatalement aussi.

    Tu ne peux donc pas renvoyer une référence non constante sur la valeur car tu briserais la const correctness au niveau de la paire, ce qui la briserait au niveau du const_iterator, ce qui impliquerait de la briser au niveau de la collection et donc au niveau de l'objet courent

    Si tu estimes que la modification de la valeur ne modifie pas l'état courent de l'objet, il faut explicitement indiquer que c'est en réalité toute la collection qui peut malgré tout être considérée comme modifiable au niveau de l'objet courent. Mais il t'appartiendra alors de faire en sorte que les accès en modification au niveau de la collection soient particulièrement encadrés
    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

Discussions similaires

  1. [RegEx] Récupération variable passé par référence
    Par Aurélien LEQUOY dans le forum Langage
    Réponses: 3
    Dernier message: 11/06/2013, 09h09
  2. Retour par référence sur const
    Par Cheps dans le forum C++
    Réponses: 3
    Dernier message: 14/12/2008, 22h36
  3. Retour de variable locale ou membre ?
    Par jph_void dans le forum C++
    Réponses: 5
    Dernier message: 25/08/2007, 21h30
  4. Fonction retour de variable par webservice
    Par Tigrou_Giyome dans le forum Services Web
    Réponses: 1
    Dernier message: 26/01/2007, 15h35
  5. Réponses: 7
    Dernier message: 13/09/2006, 16h05

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