Search code examples
c++c++20unordered-map

try_emplace in std::unordered_map without constructing temporary Key


If transparent hash and key comparison functions are used with std::unordered_map, its find has since C++20 had an overload that allows calling the function without constructing an instance of the key. However, try_emplace does not currently have such an overload, so my understanding is that an instance of Key is always constructed when the function is called.

Is there any way to replicate this behaviour of find in a function that works somewhat like try_emplace or operator[]? In other words, I would like to retrieve the old value if one exists, or emplace a new value. I could just use a combination of find and emplace but I’m guessing that emplace does some unnecessary work in this case. If I had first determined a candidate location, I could pass it to emplace_hint (like with lower_bound when using std::map), but I don’t know how to get a suitable iterator when using std::unordered_map.


Solution

  • The most efficient way to emulate the try_emplace() member function in the std::unordered_map container for heterogeneous lookup involves a combination of both the find() and emplace() member functions.

    Example:

    template <typename K, typename ...Args>
    std::pair<iterator, bool> try_emplace(K&& k, Args&& ...args)
    {
      std::pair<iterator, bool> p{this->find(k), false};
      if(p.first != this->end())
        p = this->emplace(std::forward<K>(k), std::forward<Args>(args)...);
      return p;
    }
    

    Indeed, the use of the emplace_hint() member function to exploit the already-existing iterator does not determine any performance improvement, since all the major implementations (MSVC, libc++, libstdc++) do not consider the "hint".