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

时间:2013-05-06 16:36:36

标签: c++ pointers dynamic stdmap

我在最后一天一直在解决这个问题,我仍然对以下代码的解决方案感到失望:

#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] %s\n", 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

为什么mapfind两个值相等,如果const char *@key@key@key_other


问题2

我要使用不同的容器吗?或者使用不同的代码(以不同的方式定义变量)。


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

我正在考虑创建一个我自己的发现,它会在键上找到strcmp以找出等价,但这似乎很简单,所以在我提出之前先咨询SO

任何帮助都会很棒。感谢

1 个答案:

答案 0 :(得分:8)

好。一些想法。

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

  4. 让我们修复代码中的一些错误,并继续讨论它:

    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] = '\0';
    
        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] = '\0';
    
        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] %s\n", ourmap_it->first, ourmap_it->second);
    }
    

    我在代码中引用了4个位置。我们对这些钥匙了解多少。

    嗯,我们知道(2) != (3) != (5)。但是我们推断出(1) ?= (2)的诅咒。那么,通常,(1)和(2)会有所不同。但是,标准允许(但不要求)编译器合并这两个字符串文字以节省内存。话虽如此,大多数编译器都会这样做,尤其是在一个编译单元中。

    所以,我们假设优化发生了。

    所以,让我们运行第1步。我们的地图现在看起来像:

    "hello" (1) => "world"
    

    让我们运行第2步。

     "hello" (1) => "earth"
    

    请注意,我们在地图中只有一个元素,因为(1) == (2)

    让我们运行第3步。

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

    我们现在在地图中有两个元素,因为我们使用两个不同的指针作为我们的键。

    我要停在这里,但我认为这说得很清楚。


    或者,我们可以使用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] = '\0';
    
        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] = '\0';
    
        ourmap[key] = "venus";
        ourmap[key] = "mars";
        ourmap[key_other] = "jupiter";
    
        for (ourmap_it = ourmap.begin(); ourmap_it != ourmap.end(); ++ourmap_it)
            printf("map[%s] %s\n", 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