【发布时间】: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&)不应该那么糟糕,但您可以针对您的特定输入进行测试。) -
这是一个性能问题,因为地图是在每个函数调用中首先“构建”的吗? 使您的
std::unordered_map<std::string, properties_keys>static意味着它只被初始化一次(可能在函数的第一次调用)。static变量的生命周期从(最迟)第一次访问到进程结束 - 无论它们是在函数范围内还是在函数范围外声明。 -
如果字符串比较导致性能瓶颈,您可能需要考虑重新考虑您的设计。你不希望那些在你的热门路径中。
-
只需使用 google-benchamar 编写性能测试,在发布模式下构建并进行测量。猜测哪个实现更快并不像您想象的那么容易,而且经常会出现意想不到的结果。
-
@Scheff:根据您的第一条评论:由于我实际上使用的是无序地图(参见示例),这应该是最好的变体吗?
标签: c++ string dictionary enums