在不使用if的情况下插入/更新std :: unordered_map元素的最快方法是什么?

时间:2013-10-05 12:27:00

标签: c++ performance unordered-map

我目前有很多代码如下:

std::unordered_map<int,int> my_dict;
.
.
.
// If the key does exist in the dictionary
if(my_dict.count(key) == 1){
    my_dict[key] = value;
}

// If its a new key
else{
    my_dict.insert(std::make_pair(key,value));
}

有没有什么方法可以通过每次覆盖这个值来加快速度?

5 个答案:

答案 0 :(得分:46)

你刚才(mapunordered_map

mydict[key]=value;

答案 1 :(得分:16)

我认为这可能是最快的:

auto it = my_dict.find(key);
if( it != my_dict.end() ) {
    *it = value;
}
else {
    my_dict.insert(std::make_pair(key,value));
}

如果unordered_map已经存在并且您只有一次查找,则不会修改key的结构。


如果您之后不需要/访问value,则另一个选项:

my_dict[key] = std::move(value);

如果value的分配费用昂贵且受益于移动语义,这可能会更好。

答案 2 :(得分:4)

要更新C ++ 17,您可以使用:

std::unordered_map::insert_or_assign()

http://en.cppreference.com/w/cpp/container/unordered_map/insert_or_assign

答案 3 :(得分:1)

通常,您可以通过定义一个可以避免再次输入相同内容的函数来避免额外输入。 如果您无法访问C ++ 17 insert_or_assign(),您可以自己实现以下内容:

bool InsertOrAssign(std::unordered_map& m, int key, int value) {
  // Your code or one of the suggested answers goes here
}

答案 4 :(得分:0)

您所有的地图功能都执行搜索,因此无论是否存在该键,您始终会两次搜索地图。您可以利用insert检索插入是否发生(密钥不存在)或不发生(密钥存在)并采取相应措施的事实:

std::unordered_map<int,int> mydict;
bool inserted = false;
auto position = mydict.end();
std::tie(position, inserted) = mydict.insert({key, value});
if (inserted) {
  pos->second = value;
}

这等效于mydict[key] = value,因为无论如何我们都将分配新值。对于默认构造便宜的类型,如果您只需要对地图进行操作,我会改用operator[]

在不同情况下,所有insertemplaceoperator[]都可以执行value_type的附加构造:insertemplace之前需要这样做插入会发生,并且operator[]缺省在键不存在时构造映射的值。因此,它们对于构造/复制/移动非常昂贵(std::thread,非常大的std::array ...)的类型不是理想的。在这种情况下,使用try_emplace代替(C ++ 17)更合适:

std::unordered_map<int, expensive_type> mydict;
bool inserted = false;
auto position = mydict.end();
std::tie(position, inserted) = mydict.try_emplace(key, expensive_constructor_args);
if (inserted) {
  // no expensive_type has been constructed
  // pos->second references the existing value
}