2009-07-19 13 views
1

J'utilise C++ hash_map pour stocker certaines paires de chaînes de style C. Et toutes les clés devraient être uniques pour ce cas ...problème de suppression des clés/valeurs sur STL hash_map lors de la duplication des clés

Mon problème est une fuite de mémoire sérieuse lors d'un test de stress sur plusieurs passages.

Lorsqu'aucune de ces touches dans le test ne sont identiques, il n'y a pas de fuite de mémoire. Mais avec des clés identiques est une autre histoire ...

Le hash_map (ce qui est Google sparsehash mais il met en œuvre les fonctions de SGI entièrement)

sparse_hash_map<const char*, char *, hash<const char*>, eqstr> values; 

J'ai cherché et ne pouvait pas trouver une fonction pour remplacer une clé/val paire qui a une clé identique.

values[k]=v; 

ajoute une nouvelle paire, même si la clé est la même. (un comportement que je pense devrait être toggleable) - ce n'est rien d'autre qu'un hash_map.insert()

Donc j'ai une fonction pour vérifier si la clé existe, et si elle remplace le val, et si ce n'est pas juste ajouter un nouvelle paire:

char *confFile::replaceOrStoreVal(char *k, char *v) { 
char *ret = NULL; 
values.set_deleted_key(_DIST_KEY); 
sparse_hash_map<const char*, char *, hash<const char*>, eqstr>::iterator it = 
    values.find(k); 
if(it == values.end()) 
    values[k] = v; 
else { 

// ret = it->second; // option 1 
//it->second = v;  // end option 1 

//option 2 
char *t = (char *) it->first; 
ret = it->second; 

values.erase(iter); <--- seg fault here 
free(t); 
values[k] = v; // end option 2 
} 

return ret; 
} ... and ret is later free()ed 

initialement paires sont ajoutés comme ceci:

old = replaceOrStoreVal(recordname, value); 

Il se bloque sur la première clé en double.

2 façons j'ai essayé ceci. L'option 1 entraîne une erreur de segmentation sur l'effacement (quelque chose qui m'intrigue aussi). L'option 2 ne résout pas le problème, a toujours une fuite de mémoire. Peut-être que je fais juste tout faux. Oui, je sais que je pourrais utiliser des chaînes C++, mais je ne veux pas. Essayer de garder cette vraie lumière, pour un système embarqué. Toute aide est appréciée ...

+1

Vous n'avez évidemment pas publié le vrai code - essayez de le faire, cela rend la vie plus facile pour tout le monde. –

+0

c'est le code directement à partir d'emacs. J'ai ajouté un peu plus pour aider. – EdH

Répondre

2

Vous pouvez modifier une valeur directement à l'intérieur hash_map par iterator:

ret = it->second; 

    it->second = v; // end option 2 
} 

Ce sera une solution plus rapide et plus sûre.

Vous pouvez également essayer une autre méthode de hash_map pour effacer par clé, non par iterator:

size_type erase(const key_type& k) 
0

On dirait que quelque chose d'étrange se passe. Je suppose que vous utilisez abusivement le hash_map, car ce que vous faites devrait fonctionner. En fait, ce que vous faisiez à l'origine aurait dû fonctionner.

ie.

values[k] = v; 

Remplacer ce qui était déjà présent par la clé "k" s'il existait. Puis-je vous suggérer de remplacer l'utilisation de sparse_hash_map de Google par la carte STL standard? De cette façon, vous pouvez vérifier que votre algorithme fonctionne. Ensuite, si vous remplacez std :: map par sparse_hash_map et qu'il se casse, le problème est soit avec sparse_hash_map, soit comme vous l'utilisez.

+0

sauf que si la clé est déjà là, elle ne sera pas libérée. Donc, toujours avoir une fuite de mémoire. Aussi, vous ne pouvez pas toujours libérer la clé, peu importe quoi, b/c, il ne sera pas en mesure de faire le strcmp sur les touches. – EdH

+0

Oui, vous avez raison. J'allais ajouter au bas de ma réponse que l'utilisation de char * dans une carte demandait beaucoup de soin, mais j'ai supprimé ce bit. Après réflexion, j'aurais dû laisser tomber. – Rodyland

0

Il se trouve mon code juste eu une simple erreur: j'utilisais le mauvais iterator pour trouver la clé.

Cependant, quelques points pour les personnes qui peuvent rencontrer ceci:
- vous stockez des pointeurs, pas les chaînes. Les clés dupliquées ne seront donc pas supprimées (les chaînes C elles-mêmes) sauf si vous n'ajoutez pas de clé additionnelle, et changez simplement le -> second, ou effacez toute l'entrée (et ses chaînes)
- vous devez libérer() chaîne de mémoire pour le hachage, avant que le hachage lui-même est détruit.
- l'utilisation répétée de valeurs [k] = v avec des clés en double provoque une fuite.

fonction de travail:

char *confFile::replaceOrStoreVal(char *k, char *v) { 
char *ret = NULL; 
values.set_deleted_key(_DIST_KEY); 
sparse_hash_map<const char*, char *, hash<const char*>, eqstr>::iterator it = 
    values.find(k); 
if(it == values.end()) 
    values[k] = v; 
else { 

ret = it->second; 
it->second = v; 
free(k); // we dont need this - we already have it stored. 

// char *t = (char *) it->first; 
//ret = it->second; 

//values.erase(it); // has a typo here 
//free(t); 
//values[k] = v; 
} 

return ret; 
} 

ou l'autre méthode fonctionne. Merci a tous.

Questions connexes