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

时间:2010-11-11 18:04:12

标签: c++ map stdmap

我试图弄清楚为什么以下代码不起作用,我假设使用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;
}

9 个答案:

答案 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*作为键类型,然后根据需要进行转换。 这是我的意见。