1

我正在使用 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++ 字符串,但我不想这样做。对于嵌入式系统,试图保持这种真实的光线。任何帮助表示赞赏...

4

3 回答 3

2

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

    ret = it->second;

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

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

您还可以尝试另一种 hash_map 方法来按键擦除,而不是迭代器:

size_type erase(const key_type& k)
于 2009-07-20T02:45:40.477 回答
0

似乎有什么奇怪的事情正在发生。我怀疑您在滥用 hash_map,因为您正在做的事情应该有效。事实上,你最初所做的应该是有效的。

IE。

values[k] = v;

如果存在,应该用键“k”替换已经存在的内容。

我可以建议您将 Google 的 sparse_hash_map 的使用替换为标准 STL 映射吗?这样您就可以验证您的算法是否有效。

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

于 2009-07-19T23:33:27.603 回答
0

原来我的代码只是有一个简单的错误:我使用了错误的迭代器来查找密钥。

但是,对于可能遇到这种情况的人来说,有几点需要注意:
- 您存储的是指针,而不是字符串。所以重复的键绝对不会被删除(C 字符串本身),除非您不添加添加键,而只需更改 ->second,或擦除整个条目(及其字符串)
- 您必须释放()所有字符串内存对于散列,在散列本身被破坏之前。
- 重复使用 values[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;
}

任何一种方法都有效。谢谢大家。

于 2009-07-20T04:43:18.820 回答