在重复键时删除STL hash_map上的键/值时出错

时间:2009-07-19 19:22:01

标签: c++ stl hashmap

我使用C ++ hash_map来存储一些C风格的字符串对。对于这种情况,所有键都应该是唯一的......

我的问题是在多次运行压力测试时出现严重的内存泄漏。

如果测试中的这些键都不相同,则没有内存泄漏。但是使用相同的按键却是一个不同的故事...

hash_map(这是Google的sparsehash,但它完全实现了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);  

它在第一个重复键上崩溃。

我试过这两种方式。选项1导致擦除的段错误(这也让我感到困惑)。选项2只是没有解决问题,仍然有内存泄漏。也许我只是做错了。

是的,我知道我可以使用C ++字符串,但我不想这样做。试图为嵌入式系统保持这种真正的亮点。任何帮助表示赞赏...

3 个答案:

答案 0 :(得分:2)

您可以通过迭代器直接在hash_map中更改值:

    ret = it->second;

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

这将是更快,更安全的解决方案。

您还可以尝试使用另一个hash_map方法按键擦除,而不是通过迭代器:

size_type erase(const key_type& k)

答案 1 :(得分:0)

似乎有些奇怪的事情发生了。我怀疑你是在滥用hash_map,因为你正在做的事情应该有效。事实上,你原本做的事应该有效。

values[k] = v;

如果存在,则应替换已存在的密钥“k”。

我建议你用标准的STL地图替换Google的sparse_hash_map吗?这样您就可以验证您的算法是否有效。

然后,如果用sparse_hash_map替换std :: map并且它中断,则问题出在sparse_hash_map或你使用它的方式上。

答案 2 :(得分:0)

事实证明我的代码只有一个简单的错误:我使用了错误的迭代器来找到密钥。

然而,对于可能遇到这种情况的人来说,有几点: - 你存储指针,而不是字符串。因此,除非您不添加添加键,只需更改 - &gt;秒,或删除整个条目(及其字符串),否则绝对不会删除重复键(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;
}

任何一种方法都可行。谢谢大家。