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 :

Question à propos des accesseurs constants et des std::map


Sujet :

Langage C++

  1. #1
    Membre à l'essai
    Homme Profil pro
    Inscrit en
    Septembre 2005
    Messages
    23
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 33
    Localisation : Belgique

    Informations forums :
    Inscription : Septembre 2005
    Messages : 23
    Points : 14
    Points
    14
    Par défaut Question à propos des accesseurs constants et des std::map
    Bonjour à tous,

    Voilà, j'ai un petit problème de compréhension au niveau d'un de accesseurs de ma classe personnalisée...

    Tout d'abord, voici la déclaration de la std::map

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    std::map<std::string, Object> objectsList;

    En fait, ce code provoque une erreur (no operator "[]" matches these operands):

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    const Object& MaClasse::getObject(std::string _name) const
    {
    	return objectsList[_name];
    }
    alors que celui-ci compile bien:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    const Object& MaClasse::getObject(std::string _name) const
    {
    	return objectsList.at(_name);
    }
    La différence se situe donc au niveau du at/ des "[]".

    Je ne comprends pas pourquoi ça ne fonctionne pas dans le premier cas, les deux sont censées être équivalents, non ?

    Merci pour vos réponses !

  2. #2
    Membre émérite
    Profil pro
    Inscrit en
    Novembre 2004
    Messages
    2 764
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2004
    Messages : 2 764
    Points : 2 705
    Points
    2 705
    Par défaut
    C'est d'autant plus étonnant que map<> n'est pas supposé avoir de méthode at()...

    Quel est ton environnement de développement ?

  3. #3
    Membre éclairé

    Homme Profil pro
    Inscrit en
    Octobre 2008
    Messages
    426
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Puy de Dôme (Auvergne)

    Informations forums :
    Inscription : Octobre 2008
    Messages : 426
    Points : 827
    Points
    827
    Par défaut
    Salut,

    Ne comprenant pas d’où vient le bug, j'ai fais un petit prog sur mon PC (' à partir de ton code ), et l'exemple qui plante chez toi fonctionne très bien chez moi :

    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
    #include <iostream>
    #include <string>
    #include <map>
     
    using namespace std;
     
    class MaClasse {
    	map<string, int> objectsList;
    public:
    	const int& MaClasse::getObject(std::string _name) {
    		return objectsList[_name];
    	}
     
    	void add ( std::string s, int val ) {
    		objectsList[ s ] = val;
    	}
    };
     
    void main () {
     
    	MaClasse obj;
     
    	obj.add( "aa", 10 );
    	obj.add( "bb", 20 );
    	obj.add( "cc", 30 );
     
    	int x = obj.getObject ( "bb" );
     
    	cout << "x = " << x << endl;
     
    	system ("pause");
    }
    J'ai utilisé des 'int' à la place des 'object' pour simplifier, c'est la seule différence...

    ( Moi aussi, l'utilisation de 'at' sur un map m'as étonné!! )

    Je suis sur VS2008

  4. #4
    Membre à l'essai
    Homme Profil pro
    Inscrit en
    Septembre 2005
    Messages
    23
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 33
    Localisation : Belgique

    Informations forums :
    Inscription : Septembre 2005
    Messages : 23
    Points : 14
    Points
    14
    Par défaut
    Visual Studio 2010.

    C'est ce que j'ai remarqué en regardant la Doc, mais je me suis dit que std::map devait hériter d'une classe générale de liste définissant at().

    Je n'ai pas regardé plus loin.

    Mais en tout cas at existe bien pour le std::map selon VS, il me le propose même avec IntelliSense !

    bertry : Ton code compile également chez moi !

    Le problème est que ton accesseur n'est pas constant alors que c'est de la que vient mon problème !

    Ce code, par exemple, ne compile pas:

    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
     
    #include <iostream>
    #include <string>
    #include <map>
     
    using namespace std;
     
    class MaClasse {
    	map<string, int> objectsList;
    public:
    	const int& MaClasse::getObject(std::string _name) const {
    		return objectsList[_name];
    	}
     
    	void add ( std::string s, int val ) {
    		objectsList[ s ] = val;
    	}
    };
     
    void main () {
     
    	MaClasse obj;
     
    	obj.add( "aa", 10 );
    	obj.add( "bb", 20 );
    	obj.add( "cc", 30 );
     
    	int x = obj.getObject ( "bb" );
     
    	cout << "x = " << x << endl;
     
    	system ("pause");
    }
    Mais celui-ci semble fonctionner parfaitement:

    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
     
    #include <iostream>
    #include <string>
    #include <map>
     
    using namespace std;
     
    class MaClasse {
    	map<string, int> objectsList;
    public:
    	const int& MaClasse::getObject(std::string _name) const {
    		return objectsList.at(_name);
    	}
     
    	void add ( std::string s, int val ) {
    		objectsList[ s ] = val;
    	}
    };
     
    void main () {
     
    	MaClasse obj;
     
    	obj.add( "aa", 10 );
    	obj.add( "bb", 20 );
    	obj.add( "cc", 30 );
     
    	int x = obj.getObject ( "bb" );
     
    	cout << "x = " << x << endl;
     
    	system ("pause");
    }

  5. #5
    Membre éclairé

    Homme Profil pro
    Inscrit en
    Octobre 2008
    Messages
    426
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Puy de Dôme (Auvergne)

    Informations forums :
    Inscription : Octobre 2008
    Messages : 426
    Points : 827
    Points
    827
    Par défaut
    Oups, en effet!! Je ne comprends pas pourquoi, ça modifie la compilation à ce point!!
    ligne 12 : error C2678: '[' binaire*: aucun opérateur trouvé qui accepte un opérande de partie gauche de type 'const std::map<_Kty,_Ty>' (ou il n'existe pas de conversion acceptable)
    with
    [
    _Kty=std::string,
    _Ty=int
    ]
    d:\Program Files\Microsoft Visual Studio 9.0\VC\include\map(167): peut être 'int &std::map<_Kty,_Ty>::operator [](const std::basic_string<_Elem,_Traits,_Ax> &)'
    with
    [
    _Kty=std::string,
    _Ty=int,
    _Elem=char,
    _Traits=std::char_traits<char>,
    _Ax=std::allocator<char>
    ]
    lors de la tentative de mise en correspondance de la liste des arguments '(const std::map<_Kty,_Ty>, std::string)'
    with
    [
    _Kty=std::string,
    _Ty=int
    ]

  6. #6
    Membre à l'essai
    Homme Profil pro
    Inscrit en
    Septembre 2005
    Messages
    23
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 33
    Localisation : Belgique

    Informations forums :
    Inscription : Septembre 2005
    Messages : 23
    Points : 14
    Points
    14
    Par défaut
    Bah, selon moi, VS a l'air de penser que l'opérateur [] du std::map modifie les données. C'est pourquoi il ne l'accepte pas dans une méthode constante.

    Ca me semble "logique" puisque l'opérateur [] rajoute l'élément à la liste s'il n'existe pas. Il modifie donc les données et n'est par conséquent pas utilisable dans une méthode constante.

    Mais alors comment récupérer un élément de std::map dans une méthode constante ?

    Le at semble fonctionner mais il ne le devrait pas

  7. #7
    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 : 50
    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 romit Voir le message
    Bah, selon moi, VS a l'air de penser que l'opérateur [] du std::map modifie les données. C'est pourquoi il ne l'accepte pas dans une méthode constante.

    Ca me semble "logique" puisque l'opérateur [] rajoute l'élément à la liste s'il n'existe pas. Il modifie donc les données et n'est par conséquent pas utilisable dans une méthode constante.
    En effet
    Citation Envoyé par romit Voir le message

    Mais alors comment récupérer un élément de std::map dans une méthode constante ?
    Avec map::find qui retourne map::end() si l'élément n'est pas trouvé.
    Citation Envoyé par romit Voir le message
    Le at semble fonctionner mais il ne le devrait pas
    map n'a pas de fonction at dans la norme, il doit s'agir d'une extension propriétaire. Je ne sais pas ce qu'elle fait.

  8. #8
    Membre éclairé

    Homme Profil pro
    Inscrit en
    Octobre 2008
    Messages
    426
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Puy de Dôme (Auvergne)

    Informations forums :
    Inscription : Octobre 2008
    Messages : 426
    Points : 827
    Points
    827
    Par défaut
    Mais pourquoi le compilo considère que le map est devenu constant dans une méthode constante alors que le map n'est pas déclaré constant dans la classe???
    igne 12 : error C2678: '[' binaire*: aucun opérateur trouvé qui accepte un opérande de partie gauche de type 'const std::map<_Kty,_Ty>'

  9. #9
    Membre à l'essai
    Homme Profil pro
    Inscrit en
    Septembre 2005
    Messages
    23
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 33
    Localisation : Belgique

    Informations forums :
    Inscription : Septembre 2005
    Messages : 23
    Points : 14
    Points
    14
    Par défaut
    bertry : Il ne considère pas le map constant, c'est juste que dans une méthode constante tu es obligé d'utiliser des méthodes déclarées constantes puisque tu ne peux rien modifier.

    JolyLoic, ok, merci je comprends mieux.

    Si j'ai bien compris je dois (en gros) faire ceci:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    return objectsList.find(_name)->second;

  10. #10
    Expert confirmé

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2007
    Messages
    1 895
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Septembre 2007
    Messages : 1 895
    Points : 4 551
    Points
    4 551
    Par défaut
    • map<>::find() permet de retrouver un objet selon une clef.
    • map<>::operator[]() n'existe pas en version const., donc ne peux pas être appelé sur une instance const. VS ne pense pas que la fonction va modifier l'instance de map, elle le fait (le standard décrit son fonctionnement ainsi, grosso modo : operator[] retourne (*((this->insert(make_pair(x,T()))).first)).second (ah, le plaisir du déchiffrage de code !)
    • map<>::at() n'existe pas du tout (et n'est pas mentionné dans le MSDN non plus) dans le standard ; mais le standard dit aussi spécifiquement que les implémentations de la librairie standard peuvent étendre les classes si elles le souhaitent. Ceci dit, c'est rarement une bonne chose.

  11. #11
    Membre éclairé

    Homme Profil pro
    Inscrit en
    Octobre 2008
    Messages
    426
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Puy de Dôme (Auvergne)

    Informations forums :
    Inscription : Octobre 2008
    Messages : 426
    Points : 827
    Points
    827
    Par défaut
    Citation Envoyé par romit Voir le message
    bertry : Il ne considère pas le map constant, c'est juste que dans une méthode constante tu es obligé d'utiliser des méthodes déclarées constantes puisque tu ne peux rien modifier.
    Il me semble que dans une méthode constante, c'est le développeur qui décide ce qui peut être modifié ou pas,... Pas le compilateur, non??

  12. #12
    Membre émérite

    Inscrit en
    Mai 2008
    Messages
    1 014
    Détails du profil
    Informations forums :
    Inscription : Mai 2008
    Messages : 1 014
    Points : 2 252
    Points
    2 252
    Par défaut
    Citation Envoyé par Emmanuel Deloget
    map<>::at() n'existe pas du tout (et n'est pas mentionné dans le MSDN non plus) dans le standard ;
    Ben si !?
    Citation Envoyé par 23.4.4.3 map element access

    T& at(const key_type& x);
    const T& at(const key_type& x) const;
    Returns: A reference to the element whose key is equivalent to x.
    Throws: An exception object of type out_of_range if no such element is present.
    Complexity: logarithmic.
    at() possède les deux surcharges, une pour la version const, une pour la version non-const.

    Notez que le standard a évolué recemment.

  13. #13
    Membre à l'essai
    Homme Profil pro
    Inscrit en
    Septembre 2005
    Messages
    23
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 33
    Localisation : Belgique

    Informations forums :
    Inscription : Septembre 2005
    Messages : 23
    Points : 14
    Points
    14
    Par défaut
    bertry : Non, normalement une méthode constante signifie que RIEN ne sera modifié.

    http://cpp.developpez.com/faq/cpp/?p...S_const_member

  14. #14
    Expert confirmé

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2007
    Messages
    1 895
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Septembre 2007
    Messages : 1 895
    Points : 4 551
    Points
    4 551
    Par défaut
    Citation Envoyé par Arzar Voir le message
    Ben si !?

    at() possède les deux surcharges, une pour la version const, une pour la version non-const.

    Notez que le standard a évolué recemment.
    C++11 propose at(), mais Visual C++ 2008 SP1 est basé sur C++98 + TR1 partiel. Donc dans ce cas, map<> n'est pas censé proposer de méthode at().

  15. #15
    Expert confirmé

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2007
    Messages
    1 895
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Septembre 2007
    Messages : 1 895
    Points : 4 551
    Points
    4 551
    Par défaut
    Citation Envoyé par Emmanuel Deloget Voir le message
    C++11 propose at(), mais Visual C++ 2008 SP1 est basé sur C++98 + TR1 partiel. Donc dans ce cas, map<> n'est pas censé proposer de méthode at().
    Je suis désespérément sérieux.

  16. #16
    Membre émérite

    Inscrit en
    Mai 2008
    Messages
    1 014
    Détails du profil
    Informations forums :
    Inscription : Mai 2008
    Messages : 1 014
    Points : 2 252
    Points
    2 252
    Par défaut
    Damned, si la situation est aussi désespérée, il est temps de faire un peu d'archéologie C++0xienne

    1) La méthode map::at() est apparu dans le draft N1905 datant du 19 octobre 2005 et n'a subi aucune modification depuis.

    2) La méthode map::at() n'existe PAS dans la STL de vs2008 SANS sp1.

    Je suppose donc que Microsoft a profité du SP1de vs2008 et son ajout conséquent du TR1 pour mettre à jour sa STL en fonction du draft de l'époque.

  17. #17
    Membre à l'essai
    Homme Profil pro
    Inscrit en
    Septembre 2005
    Messages
    23
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 33
    Localisation : Belgique

    Informations forums :
    Inscription : Septembre 2005
    Messages : 23
    Points : 14
    Points
    14
    Par défaut
    De toute façon c'est le 2010 que j'ai

  18. #18
    Expert confirmé

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2007
    Messages
    1 895
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Septembre 2007
    Messages : 1 895
    Points : 4 551
    Points
    4 551
    Par défaut
    Citation Envoyé par romit Voir le message
    De toute façon c'est le 2010 que j'ai
    Ma faute, j'avais mal lu l'énoncé

    VC++.Net 2010 intègre déjà quelques fonctionnalités de C++11. Ceci explique cela.

  19. #19
    Membre à l'essai
    Homme Profil pro
    Inscrit en
    Septembre 2005
    Messages
    23
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 33
    Localisation : Belgique

    Informations forums :
    Inscription : Septembre 2005
    Messages : 23
    Points : 14
    Points
    14
    Par défaut
    Y a pas de soucis, ton message m'a quand même bien aidé dans la compréhension du fonctionnement de stp::map, c'est le principal

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

Discussions similaires

  1. Réponses: 9
    Dernier message: 22/06/2015, 12h17
  2. Réponses: 9
    Dernier message: 23/07/2014, 14h11
  3. Réponses: 1
    Dernier message: 27/04/2012, 17h41
  4. Question à propos de la STL et des exceptions
    Par teddyalbina dans le forum Langage
    Réponses: 4
    Dernier message: 11/06/2011, 01h24
  5. Réponses: 21
    Dernier message: 10/02/2008, 00h09

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