【问题标题】:std::map.count using c-strings does not work?使用 c 字符串的 std::map.count 不起作用?
【发布时间】:2014-07-11 12:46:58
【问题描述】:

我希望在性能情况下使用 c-strings 而不是 std::string。我有以下代码:

std::map<const char*, int> myMap;
.
.
.
myMap.insert(std::pair<const char*, int>(str.c_str(), myint));
std::cout << myMap.count(str.c_str()) << std::endl;

奇怪的是,我刚刚输入的值对于count()返回 0?

【问题讨论】:

  • 因为它不比较你指向的字符串,它只比较指针的地址。如果它们指向相同的文本但位于内存的不同部分,则它将不起作用。您可以编写一个自定义比较函数,但我不知道它是否在我的脑海中。
  • 对于您的具体示例,如果您不更改它们之间的 str,我希望 c_str 在两个调用中返回相同的指针地址,但我不知道这是否得到保证。
  • 为什么不简单地使用std::map&lt;std::string, int&gt; myMap; 或者更好地使用枚举值作为键?
  • 您希望如何通过使用const char* 而不是std::string 来获得性能?

标签: c++ string map


【解决方案1】:

默认情况下,std::map 使用std::less 来比较键(这实际上与&lt; 相同,但它也保证可以处理不相关的指针)。这意味着它只是做指针比较,绝对不是你想要的。

只需使用 C++11 字符串类型 (std::string) 而不是用于以 nul 结尾的字符串 (const char*) 的旧类型就可以了。

【讨论】:

  • 使用std::string 的建议有很多好处:键的生命周期由映射控制,它们确实是不可变的。 const char* 可以指向可以被其他人更改的字符串,从而破坏地图。
  • std::map使用&lt;。它使用std::less。至少在理论上,这会有所不同,因为与 &lt; 的指针比较并不能正式保证正确的行为。
【解决方案2】:

为什么您认为使用原始 C 字符串会提高性能?

无论如何,std::mapchar 指针没有特殊处理。它将它们视为任何其他类型的指针,而 视为字符串,这意味着它只是将键与std::less 进行比较。可能令人困惑的是,这与 C++ 流的行为不同,后者在传递 char const * 时会以特殊方式表现。

使用std::map&lt;double *, int&gt;std::map&lt;long *, int&gt;std::map&lt;MyClass *, int&gt; 之类的内容会得到相同的行为。有趣的是,指针比较有效,因为 std::less 保证与指针一起工作,即使与 &lt; 的指针比较在形式上是未指定的行为。

因此,您显然对直接比较指针值不感兴趣。如果你想要字典字符串比较,你可以通过第三个模板参数为你的地图指定比较:

std::map<char const *, int, RawPointerComparion>

我在这个例子中称为RawPointerComparison 的东西必须是一个函子,它接受两个指针并返回第一个是否小于第二个。您可以为此使用strcmp C 函数。这应该可以解决问题:

struct RawPointerComparison
{
    bool operator()(char const *lhs, char const *rhs) const
    {
        return strcmp(lhs, rhs) < 0;
    }
};

【讨论】:

    【解决方案3】:

    您似乎使用变量str 在地图中输入不同的字符串。例如

    str = "first";
    myMap.insert( { str.c_str(), 1 } );
    
    str = "second";
    myMap.insert( { str.c_str(), 2 } );
    
    str = "first";
    std::cout << myMap.count(str.c_str()) << std::endl;
    

    在这种情况下,第一个 str.c_str() 不等于最后一个 str.c_str()(您将指针与分配的字符串进行比较),因为在这些情况下分配了不同的内存区域。

    如果你会这样做

    str = "first";
    myMap.insert( { str.c_str(), 1 } );
    std::cout << myMap.count(str.c_str()) << std::endl;
    

    如果没有中间语句,那么结果将是输出 1。

    看来你在做你不想做的事。:)

    【讨论】:

      猜你喜欢
      • 2015-03-16
      • 2018-09-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-03-10
      • 1970-01-01
      相关资源
      最近更新 更多