проблема удаления ключей / значений в STL hash_map при дублировании ключей - PullRequest
1 голос
/ 19 июля 2009

Я использую C ++ hash_map для хранения некоторых пар строк в стиле C. И все ключи должны быть уникальными для этого случая ...

Моя проблема заключается в серьезной утечке памяти при стресс-тестировании в течение нескольких прогонов.

Когда ни один из этих ключей в тесте не идентичен, утечка памяти отсутствует. Но с одинаковыми ключами это другая история ...

hash_map (это sparsehash от Google , но он полностью реализует функции SGI)

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

Я искал и не смог найти функцию для замены пары ключ / вал с идентичным ключом.

values[k]=v;

добавит только новую пару, даже если ключ тот же. (поведение, которое я считаю переключаемым) - это не что иное, как hash_map.insert ()

Итак, у меня есть функция, чтобы проверить, существует ли ключ, и заменяет ли он val, а если нет, просто добавить новую пару:

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

изначально пары добавляются так:

old = replaceOrStoreVal(recordname, value);  

Вылетает при первом дубликате ключа.

2 способа, которыми я пробовал это. Вариант 1 приводит к segfault при стирании (что меня также озадачивает). Вариант 2 просто не решает проблему, все еще есть утечка памяти. Может быть, я просто делаю все это неправильно.

Да, я знаю, что могу использовать строки C ++, но я не хочу. Попытка сохранить этот настоящий свет для встроенной системы. Любая помощь приветствуется ...

Ответы [ 3 ]

2 голосов
/ 20 июля 2009

Вы можете изменить значение непосредственно внутри hash_map через итератор:

    ret = it->second;

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

Это будет более быстрое и безопасное решение.

Вы также можете попробовать другой метод hash_map для удаления по ключу, а не по итератору:

size_type erase(const key_type& k)
0 голосов
/ 20 июля 2009

Оказывается, в моем коде просто произошла простая ошибка: я использовал неправильный итератор для поиска ключа.

Тем не менее, пара моментов для людей, которые могут столкнуться с этим:
- вы храните указатели, а не строки. Таким образом, дубликаты ключей абсолютно не будут удалены (сами строки C), если вы не добавите ключ добавления, а просто измените -> секунду или не удалите всю запись (и ее строки)
- вы должны освободить () всю строковую память для хэша, прежде чем сам хеш будет уничтожен.
- использование только значений [k] = v с повторяющимися ключами вызовет утечку.

рабочая функция:

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;
}

любой метод работает. спасибо всем.

0 голосов
/ 20 июля 2009

Кажется, что-то странное происходит. Я подозреваю, что вы неправильно используете hash_map, поскольку то, что вы делаете, должно работать. На самом деле то, что вы делали изначально, должно было сработать.

т.

values[k] = v;

Следует заменить то, что уже присутствовало, ключом "k", если оно существует.

Могу ли я предложить вам заменить использование sparse_hash_map от Google стандартной картой STL? Таким образом, вы можете проверить, работает ли ваш алгоритм.

Затем, если вы замените std :: map на sparse_hash_map, и она сломается, проблема либо в sparse_hash_map, либо в способе его использования.

...