[英]Avoiding multiple lookups in map/unordered_map
Let's say we have an expensive function mapping string
to int
and want to cache results in a map. 假设我们有一个昂贵的函数将
string
映射到int
并希望将结果缓存在映射中。
The simplest code would be 最简单的代码就是
int mapStringToIntWithCache(std::string const& s) {
static std::unordered_map<std::string, int> cache;
if (cache.count(s) > 0) return cache[s];
else return cache[s] = myExpensiveFunction(s);
}
But this has 2 lookups. 但这有2次查找。
I therefore tend to write this 因此,我倾向于写这个
int mapStringToIntWithCache(std::string const& s) {
static std::unordered_map<std::string, int> cache;
size_t sizeBefore = cache.size();
int& val = cache[s];
if (cache.size() > sizeBefore) val = myExpensiveFunction(s);
return val;
}
This has only one lookup, but seems a little clumsy. 这只有一个查找,但似乎有点笨拙。 Is there a better way?
有没有更好的办法?
Just use std::map::emplace()
method: 只需使用
std::map::emplace()
方法:
int mapStringToIntWithCache(std::string const& s) {
static std::unordered_map<std::string, int> cache;
auto pair = cache.emplace( s, 0 );
if( pair.second )
pair.first->second = myExpensiveFunction(s);
return pair.first->second;
}
Just a note to the @Slava's answer: If you pass argument by const lvalue reference, you cannot move then from this argument if it's rvalue: 只是对@ Slava的回答的一个注释:如果你通过const左值引用传递参数,那么如果它是rvalue你就不能从这个参数移动:
int i = mapStringToIntWithCache("rvalue argument here");
The temporary std::string
argument will be copied here if insertion to cache
takes place. 如果发生插入
cache
,临时的std::string
参数将被复制到此处。
You can use perfect forwarding , however, if you want to maintain arguments to be of std::string
type only (eg, for implicit conversions from string literals), then you need some wrapper-helper function solution: 你可以使用完美转发 ,但是,如果你想保持参数只是
std::string
类型(例如,对于字符串文字的隐式转换),那么你需要一些包装辅助函数解决方案:
template <typename T>
int mapStringToIntWithCacheHelper(T&& s) {
static std::unordered_map<std::string, int> cache;
auto pair = cache.emplace( std::forward<T>(s), 0 );
if( pair.second )
pair.first->second = myExpensiveFunction(pair.first->first); // can't use s here !!!
return pair.first->second;
}
int mapStringToIntWithCache(const std::string & s) {
mapStringToIntWithCacheHelper(s);
}
int mapStringToIntWithCache(std::string && s) {
mapStringToIntWithCacheHelper(std::move(s));
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.