2010-03-26 5 views
2

C'est ma première question :)Impossible d'accéder à un membre de la carte d'un pointeur

Je stocker la configuration de mon programme sous une forme Group->Key->Value, comme l'ancien INI. Je stocke l'information dans une paire de structures.

D'abord, j'utilise un std::map avec string + ptr pour les informations sur les groupes (le nom du groupe dans la clé de chaîne). La deuxième valeur std::map est un pointeur vers la structure sencond, un std::list de std::map s, avec la finition Key->Value paires.

La structure paires key-> de la valeur est créée dynamiquement, de sorte que la structure de configuration est:

std::map< std::string , std::list< std::map<std::string,std::string> >* > lv1; 

Eh bien, je suis en train de mettre en œuvre deux méthodes pour vérifier l'existence de données dans la configuration interne. Le premier, vérifier l'existence d'un groupe dans la structure:

bool isConfigLv1(std::string); 
bool ConfigManager::isConfigLv1(std::string s) { 
    return !(lv1.find(s)==lv1.end()); 
} 

La deuxième méthode, me rend fou ... Il vérifier l'existence d'une clé à l'intérieur d'un groupe.

bool isConfigLv2(std::string,std::string); 
bool ConfigManager::isConfigLv2(std::string s,std::string d) { 
    if(!isConfigLv1(s)) 
     return false; 
    std::map< std::string , std::list< std::map<std::string,std::string> >* >::iterator it; 
    std::list< std::map<std::string,std::string> >* keyValue; 
    std::list< std::map<std::string,std::string> >::iterator keyValueIt; 
    it = lv1.find(s); 
    keyValue = (*it).second; 
    for (keyValueIt = keyValue->begin() ; keyValueIt != keyValue->end() ; keyValueIt++) 
     if(!((*keyValueIt).second.find(d)==(*keyValueIt).second.end())) 
      return true; 
    return false; 
} 

Je ne comprends pas ce qui est faux. Le compilateur dit:

ConfigManager.cpp||In member function ‘bool ConfigManager::isConfigLv2(std::string, std::string)’:| 
ConfigManager.cpp|(line over return true)|error: ‘class std::map<std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::less<std::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::pair<const std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >’ has no member named ‘second’| 

Mais il doit avoir le deuxième membre, parce qu'il est un iterator carte ...

Toute suggestion au sujet de ce qui se passe?

Désolé pour mon anglais: P, et considérez que je le fais comme un exercice, je sais qu'il y a beaucoup de gestionnaires de configuration cool.

+0

Si un morceau de code a déjà été sélectionné Les instructions 'typedef', c'est tout. – Pillsy

+0

N'oubliez pas de voter sur les réponses utiles;) * (Je ne sous-entends pas que vous devez voter une certaine réponse, mais que le vote est l'une des principales caractéristiques de SO - voir la FAQ pour plus de détails.) * –

Répondre

2

keyValueIt n'est pas un itérateur de carte, c'est un itérateur de liste. Vous pouvez juste faire

if (keyValueIt->find(d) != keyValueIt->end()) 
+0

n'est pas une liste :: itérateur, c'est une liste > :: itérateur. Il ne peut pas trouver d. – Beta

+0

'* keyValueIt' donne un' map' et vous pouvez utiliser 'map :: find (key)' dessus. –

+0

Vous avez raison, mon erreur. – Beta

1

Si vous voulez juste une structure group/key/value vous êtes trop compliquer, vous avez un niveau plus dans votre structure de données alors nécessaire.
Le list supplémentaire n'est pas nécessaire, une map de maps suffit:

// typedefs for readability: 
typedef std::map<std::string, std::string> Entries; 
typedef std::map<std::string, Entries> Groups; 
// class member: 
Groups m_groups; 

bool ConfigManager::hasKey(const std::string& group, const std::string& key) 
{   
    Groups::const_iterator it = m_groups.find(group); 
    if(it == m_groups.end()) 
     return false; 

    const Entries& entries = it->second; 
    return (entries.find(key) != entries.end()); 
} 
+0

Merci. Maintenant, je fais quelque chose comme ça;) – fjfnaranjo

1

Je pense que Joel est correct avec

if (keyValueIt->find(d) != keyValueIt->end()) 

Cependant, je voulais vous encourager l'utilisation des typedefs pour essayer de simplifier votre code. L'utilisation typedefs peut aider pour diagnostiquer des problèmes comme celui-ci (et si vous êtes chanceux, votre compilateur vous donnera des messages d'erreur plus significatifs en raison

Par exemple:.

typedef std::map<std::string,std::string> KeyValueMap; 
typedef std::list<KeyValueMap> ConfigurationList; 
typedef std::map< std::string, ConfigurationList* > ConfigurationMap; 

bool isConfigLv2(std::string,std::string); 
bool ConfigManager::isConfigLv2(std::string s,std::string d) { 
    if(!isConfigLv1(s)) 
     return false; 

    ConfigurationMap::iterator it; 
    ConfigurationList* keyValue; 
    ConfigurationList::iterator keyValueIt; // <- it's not a keyValue iterator, it's a ConfigList iterator! 
    it = lv1.find(s); 
    keyValue = (*it).second; 
    for (keyValueIt = keyValue->begin() ; keyValueIt != keyValue->end() ; keyValueIt++) 
     if(!((*keyValueIt).second.find(d)==(*keyValueIt).second.end())) 
      return true; 
    return false; 
} 

Simplifier les types rend plus évident pour moi, keyValueIt est probablement mal interprété (c.-à-d. en fait un itérateur de liste, et non un itérateur KeyValueMap et donc l'accès '.second' est erroné.)

+0

PS mes noms de typedef sont assez mauvais. Cela vaut la peine de passer du temps à trouver de bons noms descriptifs :) – HulkHolden

+0

Ne vous inquiétez pas, l'idée est bonne. gf le reprend assez bien dans le commentaire suivant. – fjfnaranjo

Questions connexes