使用char *作为std :: map中的键

我想弄清楚为什么下面的代码不工作,我假设这是使用char *作为键types的问题,但我不知道如何解决它或为什么发生。 我使用的所有其他函数(在HL2 SDK中)都使用char*所以使用std::string会导致很多不必要的复杂性。

 std::map<char*, int> g_PlayerNames; int PlayerManager::CreateFakePlayer() { FakePlayer *player = new FakePlayer(); int index = g_FakePlayers.AddToTail(player); bool foundName = false; // Iterate through Player Names and find an Unused one for(std::map<char*,int>::iterator it = g_PlayerNames.begin(); it != g_PlayerNames.end(); ++it) { if(it->second == NAME_AVAILABLE) { // We found an Available Name. Mark as Unavailable and move it to the end of the list foundName = true; g_FakePlayers.Element(index)->name = it->first; g_PlayerNames.insert(std::pair<char*, int>(it->first, NAME_UNAVAILABLE)); g_PlayerNames.erase(it); // Remove name since we added it to the end of the list break; } } // If we can't find a usable name, just user 'player' if(!foundName) { g_FakePlayers.Element(index)->name = "player"; } g_FakePlayers.Element(index)->connectTime = time(NULL); g_FakePlayers.Element(index)->score = 0; return index; } 

你需要给映射赋予一个比较函数,否则它会比较char *指针而不是string。 一般情况下,任何时候你都希望你的地图键是一个指针。

即。

 struct cmp_str { bool operator()(char const *a, char const *b) { return std::strcmp(a, b) < 0; } }; map<char *, int, cmp_str> BlahBlah; 

编辑:Acutally无视我的编辑,仿函数更容易使用。

你不能使用char*除非你绝对100%确定你要用完全相同的指针访问地图,而不是string。

例:

 char *s1; // pointing to a string "hello" stored memory location #12 char *s2; // pointing to a string "hello" stored memory location #20 

如果您使用s1访问地图,您将获得与使用s2访问地图不同的位置。

两个C风格的string可以有相同的内容,但在不同的地址。 而那个map比较指针,而不是内容。

转换为std::map<std::string, int>的成本可能不如您想象的那么多。

但是,如果你真的需要使用const char*作为映射键,请尝试:

 #include <functional> #include <cstring> struct StrCompare : public std::binary_function<const char*, const char*, bool> { public: bool operator() (const char* str1, const char* str2) const { return std::strcmp(str1, str2) < 0; } }; typedef std::map<const char*, int, StrCompare> NameMap; NameMap g_PlayerNames; 

你可以使用std::map<const char*, int> ,但是不能使用非const指针(注意为键添加了const ),因为当映射将它们引用为键。 (虽然地图通过使它们成为const保护它的键,但是这只会使指针变得混乱,而不是它指向的string)。

但是,你为什么不简单地使用std::map<std::string, int> ? 它可以在没有头痛的情况下使用。

您正在比较使用char *来使用string。 他们不一样。

char *是指向char的指针。 最终,它是一个整数types的值被解释为char的有效地址。

一个string是一个string。

容器能够正常工作,但是作为键的容器,其中的键是char * ,值是int

正如其他人所说,在这种情况下,你可能应该使用std :: string而不是char *,尽pipe如果这是真正需要的指针作为关键字原则上没有任何错误。

我认为这个代码不起作用的另一个原因是因为一旦你在地图中find一个可用的条目,你试图用相同的键(char *)将它重新插入到地图中。 由于该键已经存在于您的地图中,插入将失败。 map :: insert()的标准定义了这种行为…如果键值存在,则插入失败并且映射的值保持不变。 然后它被删除。 您需要先删除它,然后重新插入。

即使你把char *改成std :: string,这个问题仍然会存在。

我知道这个主题已经很老了,现在你已经修好了,但是我没有看到有人提出这个观点,所以为了未来的观众我正在回答。

当我尝试在多个源文件中查找元素时,很难将char *用作映射键。 当在插入元素的同一个源文件中进行所有的访问/查找时,它工作正常。 但是,当我尝试使用另一个文件中的查找来访问该元素时,我无法获取绝对在地图内的元素。

原因是Plabo指出,指针(每个编译单元都有自己的常量char *)在另一个cpp文件中访问时并不相同。

只要支持比较( <>== )和赋值,使用任何键types都没有问题。

有一点应该提到 – 考虑到你正在使用模板类。 因为编译器会为char*int*生成两个不同的实例。 而两者的实际代码将几乎相同。

因此 – 我会考虑使用void*作为键types,然后根据需要进行转换。 这是我的意见。