C++ 在 std::map 中使用 char* 作为键

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4157687/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-28 14:39:36  来源:igfitidea点击:

Using char* as a key in std::map

c++mapstdmap

提问by Josh Renwald

I am trying to figure out why the following code is not working, and I am assuming it is an issue with using char* as the key type, however I am not sure how I can resolve it or why it is occuring. All of the other functions I use (in the HL2 SDK) use char*so using std::stringis going to cause a lot of unnecessary complications.

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

回答by GWW

You need to give a comparison functor to the map otherwise it's comparing the pointer, not the null-terminated string it points to. In general, this is the case anytime you want your map key to be a pointer.

您需要为映射提供一个比较函子,否则它将比较指针,而不是它指向的以空字符结尾的字符串。通常,只要您希望地图键成为指针,就会出现这种情况。

For example:

例如:

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

map<char *, int, cmp_str> BlahBlah;

回答by Pablo Santa Cruz

You can't use char*unless you are absolutely 100% sure you are going to access the map with the exact same pointers, not strings.

char*除非您绝对 100% 确定您将使用完全相同的指针而不是字符串访问地图,否则您不能使用。

Example:

例子:

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

If you access map with s1you will get a different location than accessing it with s2.

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

回答by aschepler

Two C-style strings can have equal contents but be at different addresses. And that mapcompares the pointers, not the contents.

两个 C 风格的字符串可以具有相同的内容但位于不同的地址。这map比较的是指针,而不是内容。

The cost of converting to std::map<std::string, int>may not be as much as you think.

转换为的成本std::map<std::string, int>可能没有你想象的那么多。

But if you really do need to use const char*as map keys, try:

但是,如果您确实需要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;

回答by Daniel Daranas

You are comparing using a char *to using a string. They are not the same.

您正在比较使用 achar *和使用字符串。她们不一样。

A char *is a pointer to a char. Ultimately, it is an integer type whose value is interpreted as a valid address for a char.

Achar *是指向字符的指针。最终,它是一个整数类型,其值被解释为 a 的有效地址char

A string is a string.

一个字符串是一个字符串。

The container works correctly, but as a container for pairs in which the key is a char *and the value is an int.

容器正常工作,但作为键为 achar *且值为 an 的对的容器int

回答by sbi

You can get it working with std::map<const char*, int>, but must not use non-constpointers (note the added constfor the key), because you must not change those strings while the map refers to them as keys. (While a map protects its keys by making them const, this would only constify the pointer, not the string it points to.)

您可以使用std::map<const char*, int>,但不能使用非const指针(注意const为键添加的),因为当映射将它们称为键时,您不能更改这些字符串。(虽然映射通过创建它们来保护它的键const,但这只会构造指针,而不是它指向的字符串。)

But why don't you simply use std::map<std::string, int>? It works out of the box without headaches.

但你为什么不简单地使用std::map<std::string, int>?它开箱即用,不会让人头疼。

回答by Toby Mitchell

As the others say, you should probably use std::string instead of a char* in this case although there is nothing wrong in principle with a pointer as a key if that's what is really required.

正如其他人所说,在这种情况下,您可能应该使用 std::string 而不是 char* ,尽管原则上如果确实需要,将指针作为键没有任何问题。

I think another reason this code isn't working is because once you find an available entry in the map you attempt to reinsert it into the map with the same key (the char*). Since that key already exists in your map, the insert will fail. The standard for map::insert() defines this behaviour...if the key value exists the insert fails and the mapped value remains unchanged. Then it gets deleted anyway. You'd need to delete it first and then reinsert.

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

Even if you change the char* to a std::string this problem will remain.

即使您将 char* 更改为 std::string 这个问题仍然存在。

I know this thread is quite old and you've fixed it all by now but I didn't see anyone making this point so for the sake of future viewers I'm answering.

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

回答by Jie Xu

Had a hard time using the char* as the map key when I try to find element in multiple source files. It works fine when all the accessing/finding within the same source file where the elements are inserted. However, when I try to access the element using find in another file, I am not able to get the element which is definitely inside the map.

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

It turns out the reason is as Plabopointed out, the pointers (every compilation unit has its own constant char*) are NOT the same at all when it is accessed in another cpp file.

事实证明,原因正如Plabo 所指出的,在另一个 cpp 文件中访问时,指针(每个编译单元都有自己的常量 char*)根本不相同。

回答by valdo

There's no problem to use any key type as long as it supports comparison (<, >, ==) and assignment.

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

One point that should be mentioned - take into account that you're using a templateclass. As the result compiler will generate two different instantiations for char*and int*. Whereas the actual codeof both will be virtually identical.

应该提到的一点 - 考虑到您正在使用模板类。其结果是,编译器会产生两个不同的实例char*int*。而两者的实际代码实际上是相同的。

Hence - I'd consider using a void*as a key type, and then casting as necessary. This is my opinion.

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