【问题标题】:C++ Mapping strings to enums - string compare vs. map - performance optimizationC++ 将字符串映射到枚举 - 字符串比较与映射 - 性能优化
【发布时间】:2020-09-18 10:36:09
【问题描述】:

在我的代码中,我必须将输入字符串映射到枚举值。这种映射经常使用,根据性能分析,它是一个瓶颈。 实际上,我将输入字符串与所有可能的字符串值(if/then)进行比较,然后返回正确的枚举值。

有大约 50 个不同的值可供比较。

例子:

enum properties_keys {
PROP_EXPANSION,
PROP_DIGITS,
PROP_INVALID,
//others...};

比较功能:

properties_keys convertPropString(std::string input)
{
   if (input.compare("prop.expansion") == 0)
      return PROP_EXPANSION;
   if (input.compare("prop.digits") == 0)
      return PROP_DIGITS;
   //others...
   return PROP_INVALID;
}

替代方案:使用地图

例子:

properties_keys convertPropString(std::string input) {
    static std::unordered_map<std::string, properties_keys> const propStrings{
        { "prop.expansion", PROP_EXPANSION},
        { "prop.digits", PROP_DIGITS},
        //...
    };

    auto it = propStrings.find(input);
    if (it != propStrings.end()) {
        return it->second;
    }
    else { return PROP_INVALID; }
}

问题

  • 关于这两种变体在性能方面是否存在显着差异,是否有任何发现?如果是这样,哪个选项更好?
  • 是否有更好(更快)的方法来解决任务?
  • 如果您将变体与地图一起使用,在函数之外定义地图会更好吗?或者换一种说法:这是因为每次函数调用都首先“构建”映射而导致性能问题吗?

感谢所有专家。

【问题讨论】:

  • std::map::find() 保证了 O(ld N) 而你的 if 级联有 O(N)。比std::map::find() 更快的是std::unordered_map::find()。它可以导致具有合理散列函数的 O(1)。 (我认为std::hash(const std::string&amp;) 不应该那么糟糕,但您可以针对您的特定输入进行测试。)
  • 这是一个性能问题,因为地图是在每个函数调用中首先“构建”的吗? 使您的 std::unordered_map&lt;std::string, properties_keys&gt; static 意味着它只被初始化一次(可能在函数的第一次调用)。 static 变量的生命周期从(最迟)第一次访问到进程结束 - 无论它们是在函数范围内还是在函数范围外声明。
  • 如果字符串比较导致性能瓶颈,您可能需要考虑重新考虑您的设计。你不希望那些在你的热门路径中。
  • 只需使用 google-benchamar 编写性能测试,在发布模式下构建并进行测量。猜测哪个实现更快并不像您想象的那么容易,而且经常会出现意想不到的结果。
  • @Scheff:根据您的第一条评论:由于我实际上使用的是无序地图(参见示例),这应该是最好的变体吗?

标签: c++ string dictionary enums


【解决方案1】:

使用std::unordered_map&lt;std::string, whatever&gt; 意味着为每个字符串文字创建一个字符串,并为每个映射条目创建一个节点。这对动态内存有很多影响。

对于一组固定的东西,我倾向于将地图手动滚动为文件范围的元素数组,每个元素由const char* 和相应的值组成。元素按名称手动排序。

struct element {
    const char *name;
    properties_keys value;
};

element element_map[] = {
    { "prop.digits", PROP_DIGITS },
    { "prop.expansion", PROP_EXPANSION },
    ...
};

在极少数情况下,当枚举数发生更改时,您必须管理更改,保持所有元素按字母顺序排列。如果你偏执(而且你应该如此),请在启动时做一些事情来检查顺序是否正确。

使用std::binary_search 和适当的谓词查找元素。

【讨论】:

  • 好吧,为了确保“手动”对表格进行编码/排序没有错误,可以使用带有 lambda 的断言,以确保每个元素小于其后继元素。 (我就是这些偏执狂中的一员……)
猜你喜欢
  • 2021-11-09
  • 2019-01-29
  • 1970-01-01
  • 2019-09-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-01-06
相关资源
最近更新 更多