std::map 其中键是动态的或字符串文字

std::map where key's are dynamic or string literal

本文关键字:文字 动态 字符串 map std      更新时间:2023-10-16

我在最后一天一直在处理这个问题,我仍然失去了以下代码的解决方案:

#include <stdio.h>
#include <iostream>
#include <map>
int main()
{
    std::map<char *, char *> ourmap;
    std::map<char *, char *>::iterator ourmap_it;
    ourmap["hello"] = "world";
    ourmap["hello"] = "earth";
    char * key = new char[5];
    key[0] = 'h';
    key[1] = 'e';
    key[2] = 'l';
    key[3] = 'l';
    key[4] = 'o';
    char * key_other = new char[5];
    key_other[0] = 'h';
    key_other[1] = 'e';
    key_other[2] = 'l';
    key_other[3] = 'l';
    key_other[4] = 'o';
    ourmap[key] = "venus";
    ourmap[key] = "mars";
    ourmap[key_other] = "jupiter";
    for (ourmap_it = ourmap.begin(); ourmap_it != ourmap.end(); ++ourmap_it)
    {
        printf("map[%s] %sn", ourmap_it->first, ourmap_it->second);
    }
    ourmap.clear();
    delete key;
    delete key_other;
    return 0;
}

键没有被覆盖,如果在动态键上执行find,也会有相同的行为。输出更详细地解释了

map[hello] earth
map[hello] mars
map[hello] jupiter

问题1

const char *@key@key@key_other的情况下,为什么map不是find使两个值相等?


问题2

我应该使用不同的容器吗?或者使用不同的代码(定义不同的变量)。


在上面的代码中使用动态键是没有意义的,但是我的实际代码需要动态键,如果键值是从文件中读取的,而不是在代码中定义的,因为我不知道给定文件中键的大小,所以它必须是动态的。问题是,虽然我可以设置键,但我不能检索值。

我想创建一个我自己的发现,它在键上做一个strcmp来找出等价,但这似乎很糟糕,所以在我绑定它之前只是咨询SO

任何帮助都太好了。由于

好的。一些想法。

    你正在引起一些未定义的行为。您为一个字符串分配5个字节,并在该内存中放入"hello",但是您没有足够的空间来null终止它。当你试图打印它时,会发生未定义的行为。
  1. 不能保证字符串字面值"hello"的两个实例具有相同的指针。标准将这个选项留给了实现。
  2. 我会用std::string代替char *来解决你的大部分问题。

让我们修复你代码中的一些bug,然后继续讨论:

int main() {
    std::map<char const *, char const *> ourmap;
    std::map<char const *, char const *>::iterator ourmap_it;
    ourmap["hello"] = "world";  // (1)
    ourmap["hello"] = "earth";  // (2)
    char * key = new char[6];
    key[0] = 'h';
    key[1] = 'e';
    key[2] = 'l';
    key[3] = 'l';
    key[4] = 'o';
    key[5] = '';
    char * key_other = new char[6];
    key_other[0] = 'h';
    key_other[1] = 'e';
    key_other[2] = 'l';
    key_other[3] = 'l';
    key_other[4] = 'o';
    key_other[5] = '';
    ourmap[key] = "venus"; // (3)
    ourmap[key] = "mars";  // (4)
    ourmap[key_other] = "jupiter"; // (5)
    for (ourmap_it = ourmap.begin(); ourmap_it != ourmap.end(); ++ourmap_it)
        printf("map[%s] %sn", ourmap_it->first, ourmap_it->second);
}

我在代码中引用了4个位置。关于这些键我们知道些什么?

我们知道(2) != (3) != (5)。但是我们能从(1) ?= (2)推断出什么呢?通常情况下,(1)和(2)是不同的。然而,标准的允许(但不要求)编译器合并这两个字符串字面值以节省内存。也就是说,大多数编译器都这样做,特别是在一个编译单元内。

那么,让我们假设优化发生了

那么,让我们运行步骤1。我们的映射现在看起来像:

"hello" (1) => "world"

让我们运行第二步。

 "hello" (1) => "earth"

注意,我们仍然只有一个元素在映射中,因为(1) == (2) .

让我们运行第三步。

 "hello" (1) => "earth"
 "hello" (3) => "venus"

现在map中有两个元素,因为使用了两个不同的指针作为键。

我就讲到这里,但我想我已经讲得很清楚了。


或者,我们可以使用std::string。

int main() {
    std::map<std::string, std::string> ourmap;
    std::map<std::string, std::string>::iterator ourmap_it;
    ourmap["hello"] = "world";
    ourmap["hello"] = "earth";
    char * key = new char[6];
    key[0] = 'h';
    key[1] = 'e';
    key[2] = 'l';
    key[3] = 'l';
    key[4] = 'o';
    key[5] = '';
    char * key_other = new char[6];
    key_other[0] = 'h';
    key_other[1] = 'e';
    key_other[2] = 'l';
    key_other[3] = 'l';
    key_other[4] = 'o';
    key_other[5] = '';
    ourmap[key] = "venus";
    ourmap[key] = "mars";
    ourmap[key_other] = "jupiter";
    for (ourmap_it = ourmap.begin(); ourmap_it != ourmap.end(); ++ourmap_it)
        printf("map[%s] %sn", ourmap_it->first.c_str(), ourmap_it->second.c_str());
}

这里的输出是:

map[hello] jupiter

这是因为std::string实现<char *不同。比较字符串的内容。


再扩展一下最后一件事。下面是实现比较器的一个示例。

struct comparator {
    bool operator()(const char * lhs, const char * rhs) const {
        return strcmp(lhs, rhs) < 0;
    }
};
int main() {
    std::map<char const *, char const *, comparator> ourmap;
    std::map<char const *, char const *, comparator>::iterator ourmap_it;
...

在本例中,就像std::string一样,我们将看到以下输出:

map[hello] jupiter