简体   繁体   English

避免在map / unordered_map中进行多次查找

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM