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.