如何在unordered_map中设置值并查明是否添加了新密钥

use*_*895 3 c++ dictionary unordered-map hashmap c++11

如何有效地和惯用地设置一个值,unordered_map 找出是否添加了新密钥:

#include <unordered_map>
#include <string>

int main() {
  auto map = std::unordered_map<std::string, int>{{"foo", 1}, {"bar", 2}};

  map["foo"] = 3;
  // how to find out if a new key was added?
}
Run Code Online (Sandbox Code Playgroud)

我不能insert()直接使用,因为我想要覆盖该值,如果已经存在并且insert不这样做.我无法operator[]直接使用,因为它不提供有关是否添加新密钥的信息.

出于性能原因,我想避免在地图中进行两次搜索.

我在其他地方看到的一个技巧是获取引用并检查该值是否为默认构造:

auto& value = map["foo"];
if(value == 0) {
    // am inserting a new key
}
value = 3;
Run Code Online (Sandbox Code Playgroud)

但我可以在我的地图中真正拥有默认构造值,因此默认构造值不是新密钥的良好指示.

到目前为止我能想出的最好的是:

auto size_before = map.size();
map["foo"] = 3;
if (map.size() > size_before) {
    // am inserting a new key
}
Run Code Online (Sandbox Code Playgroud)

这看起来很难看,它假设得到一个unordered_map便宜的大小(是吗?).

它似乎unordered_map::insert_or_assign可能是我的祈祷的答案,但遗憾的是它来自C++ 17所以我可能不会再使用它5年左右.想要这样做似乎很常见,我认为目前必须采取合理的方式.

Jar*_*d42 5

您可以使用std::unordered_map::insert和测试结果.

有辅助功能:

template<typename Map, typename T>
std::pair<typename Map::iterator, bool>
insert_or_assign(Map& m, const typename Map::key_type& k, const T& t)
{
    auto p = m.insert({k, t});
    if (!p.second) {
        // overwrite previous value
        p.first->second = t;
    }
    return p;
}
Run Code Online (Sandbox Code Playgroud)

然后

auto p = insert_or_assign(map, "foo", 3);
if (p.second) {
    // inserted
} else {
    // assigned
}
Run Code Online (Sandbox Code Playgroud)

现场演示