我试图弄清楚为什么以下代码不起作用,我假设使用char *作为密钥类型是一个问题,但是我不知道如何解决它或为什么会发生它。我使用的所有其他功能(在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;
}
答案 0 :(得分:123)
你需要给地图提供一个比较仿函数,否则它会比较指针,而不是它指向的以空字符结尾的字符串。通常,只要您希望地图键成为指针,就会出现这种情况。
例如:
struct cmp_str
{
bool operator()(char const *a, char const *b) const
{
return std::strcmp(a, b) < 0;
}
};
map<char *, int, cmp_str> BlahBlah;
答案 1 :(得分:44)
除非您完全100%确定要使用完全相同的指针访问地图,而不是字符串,否则您无法使用char*
。
示例:
char *s1; // pointing to a string "hello" stored memory location #12
char *s2; // pointing to a string "hello" stored memory location #20
如果您使用s1
访问地图,则会获得与使用s2
访问地图不同的位置。
答案 2 :(得分:22)
两个C风格的字符串可以具有相同的内容但位于不同的地址。并且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;
答案 3 :(得分:8)
您正在使用char *
与使用字符串进行比较。它们不一样。
char *
是指向char的指针。最终,它是一个整数类型,其值被解释为char
的有效地址。
字符串是一个字符串。
容器可以正常工作,但是作为密钥为char *
且价值为int
的对的容器。
答案 4 :(得分:8)
您可以使用std::map<const char*, int>
,但不能使用非const
指针(请注意为密钥添加了const
),因为您不能更改这些字符串。 map将它们称为键。 (虽然地图通过使它们const
来保护其密钥,但这只会影响指针,而不是它所指向的字符串。)
但为什么不简单地使用std::map<std::string, int>
?它开箱即用,没有头痛。
答案 5 :(得分:2)
正如其他人所说,在这种情况下你可能应该使用std :: string而不是char *,尽管原则上指针作为键是没有错的,如果这是真正需要的。
我认为此代码无效的另一个原因是,一旦在地图中找到可用条目,您就会尝试使用相同的密钥(char *)将其重新插入到地图中。由于该键已存在于地图中,因此插入将失败。 map :: insert()的标准定义了这种行为......如果键值存在,则插入失败并且映射值保持不变。然后它会被删除。您需要先删除它,然后重新插入。
即使将char *更改为std :: string,也会出现此问题。
我知道这个帖子已经很老了,你现在已经解决了所有问题,但我没有看到有人提出这一点,所以为了我将来回答的未来观众。
答案 6 :(得分:0)
当我尝试在多个源文件中查找元素时,很难将char *用作映射键。当所有访问/查找在插入元素的同一源文件中时,它工作正常。但是,当我尝试使用另一个文件中的find访问该元素时,我无法获得肯定在地图中的元素。
事实证明原因是Plabo指出,指针(每个编译单元都有自己的常量char *)在另一个cpp文件中访问时根本不相同。
答案 7 :(得分:0)
std::map<char*,int>
将使用默认的std::less<char*,int>
比较char*
键,这将进行指针比较。但是您可以这样指定自己的Compare类:
class StringPtrCmp {
public:
StringPtrCmp() {}
bool operator()(const char *str1, const char *str2) const {
if (str1 == str2)
return false; // same pointer so "not less"
else
return (strcmp(str1, str2) < 0); //string compare: str1<str2 ?
}
};
std::map<char*, YourType, StringPtrCmp> myMap;
请记住,您必须确保char *指针有效。
我建议还是使用std::map<std::string, int>
。
答案 8 :(得分:-5)
使用任何密钥类型都没有问题,只要它支持比较(<
,>
,==
)和分配。
应该提到的一点 - 考虑到您使用的是模板类。结果编译器将为char*
和int*
生成两个不同的实例化。而两者的实际代码几乎完全相同。
因此 - 我会考虑使用void*
作为键类型,然后根据需要进行转换。
这是我的意见。