C++ 在stl映射中插入新项时,会覆盖第一个元素
首先,我有以下代码:C++ 在stl映射中插入新项时,会覆盖第一个元素,c++,stl,stdmap,C++,Stl,Stdmap,首先,我有以下代码: map<char*, char*> records; // id, value are buffer variables to store the text that returns from `strcpy()` char *id = (char*)malloc(sizeof(char*) * 20); char *value = (char*)malloc(sizeof(char*) * 20); sql->open(dbFile); sql-&
map<char*, char*> records;
// id, value are buffer variables to store the text that returns from `strcpy()`
char *id = (char*)malloc(sizeof(char*) * 20);
char *value = (char*)malloc(sizeof(char*) * 20);
sql->open(dbFile);
sql->query("SELECT * FROM categories");
while(sql->fetch() != SQLITE_DONE){
// copy the text that returns from `sql->getValue`, then convert that text from `const unsigned char*` to `const char*`
strcpy(id, reinterpret_cast<const char*>(sql->getValue(0)));
strcpy(value, reinterpret_cast<const char*>(sql->getValue(1)));
// insert the values that in `id`,`value` as new item
records.insert(pair<char*, char*>(id, value));
}
free(id);
free(value);
前面代码的思想是使用strcopy复制返回此方法sql->getValue0的文本,然后将该文本从const unsigned char*转换为const char*,然后将这些文本存储在id、value变量中,然后将id、value作为新项插入。
前面的步骤发生在从数据库获取的每个数据上
进一步澄清这一想法:
例如,从数据库中获取三行:水果、蔬菜、糖果。
当然,当将这三个数据插入地图容器时,容器中的项目数将是三个项目第一个水果、第二个蔬菜、第三个糖果
在我的例子中,当检查物品的数量时,我发现只有一种物品,而且是糖果
现在,我很惊讶,其余的项目在哪里?您正在覆盖相同的内存块三次,并存储指向这些内存块的指针三次。就地图而言,它每次都是相同的值,因为指针永远不会改变 看起来您真正想要的是字符串映射,而不是指针。如果使用std::string,这将更加容易:
这还具有使代码异常安全的优点,至少在没有try-catch块的字符串中是如此。std::string的析构函数将处理清理,无论作用域如何保留。std::map使用的键不是id,而是id的char*。我建议您使用std::string,因为我认为您也存在内存泄漏。在上一个问题中,您被告知char*映射是一个糟糕的设计。这是可以做到的,但你会有一个内存管理混乱,就像在这段代码中一样。@Galik:谢谢,确切地说,我知道这一点,但不知道如何在不使用字符串类型的情况下解决这个问题。@Blastfurne:是的,但是我使用stl映射只是为了模拟关联数组。@LionKing:每次调用insert时,都会为键/值对传递相同的地址。这就是std::map看到的所有内容,两个指针。它不会跟随指针查看字符串或进行复制。您可以在调用之间修改char数组的内容,但std::map不知道这一点。循环结束后,您将释放内存,这将在std::map中留下悬空指针。谢谢,但除了使用字符串类型之外,没有其他方法?@LionKing:您可以为插入std::map中的每个字符串分配内存,并确保在正确的时间手动释放该内存,并且只释放一次。或者您可以让std::string为您正确管理该资源……确实有,但您不想使用它。说真的,这比癌症更糟糕,这是非常糟糕的事情。您必须为循环中的新C字符串分配新内存,将值复制到它们中,并将它们存储在映射中。您必须手动清理所有这些C样式的字符串。您必须对所有这些分配执行错误处理。如果映射要保持排序,则必须为映射提供一个使用C样式字符串的比较函子。你真的不想做那种事。相信我和其他人。@blastburne:谢谢,我想我会使用字符串类型。
#include <string>
...
map<string, string> records;
string id, value; // size of allocation will be handled by the string class.
sql->open(dbFile);
sql->query("SELECT * FROM categories");
while(sql->fetch() != SQLITE_DONE){
// string has an assignment operator from C-style strings
id = reinterpret_cast<const char*>(sql->getValue(0));
value = reinterpret_cast<const char*>(sql->getValue(1));
// more readable way of writing the insert. id, value will be copied into
// the map.
records[id] = value;
}
// freeing unnecessary; string class handles it when id, value go out of scope.