为什么C++ map.insert()不能覆盖

62o28rlo  于 2022-11-19  发布在  其他
关注(0)|答案(5)|浏览(514)

在下面的代码中:

#include <map>
#include <utility>
#include <iostream>

using namespace std;

int main(){
  pair<int,int> p1(1,1);
  pair<int,int> p2(1,2);

  map<int,int> m;
  m.insert(p1);
  m.insert(p2);

  cout << "Map value: "<< m.at(1) << endl;

}

它打印出:Map value: 1,为什么m.insert(p2)不覆盖Map中的上一个实体?

nnsrf1az

nnsrf1az1#

map.insert()仅在容器尚未包含具有等效键的元素时插入。
您应该改用operator[]

m[p2.first] = p2.second;
k7fdbhmy

k7fdbhmy2#

std::map::insert参考文献中指出:
如果容器尚未包含具有等效键的元素,则将元素插入容器。

kzmpq1sx

kzmpq1sx3#

自C++17起更新现在有std::map::insert_or_assign()成员函数:

m.insert_or_assign(p1);

顾名思义,如果键已经存在,那么值就被赋值(并且保留键对象),而不是擦除并重新复制构造键和值。(所以它相当于下面两个C++17之前的代码片段中的第一个。)
如果你想要一个迭代器指向(新的或更新的)元素,你需要再次从返回的对中选择值。

auto [it, wasInserted] = m.insert_or_assign(p1);

在C++17之前把其他答案放在一起,如果你想避免默认可构造的假设,你会得到如下所示的插入并覆盖代码:

auto itAndWasInserted = m.insert(p1);
if (!itAndWasInserted.second) {
    *(itAndWasInserted.first) = p1;
}

在上面的代码片段中,如果元素已经存在,那么就给它赋新值。这通常是你想要的。如果你想构造而不是赋新值,但仍然想避免第二次搜索(在你擦除原始值之后),你最终会得到这个怪物:

auto itAndWasInserted = m.insert(p1);
auto it = itAndWasInserted.first;
if (!itAndWasInserted.second) {
    auto afterIt = m.erase(it);
    auto newItAndWasInserted = m.insert(afterIt, p1);  // Hint form of insert
    it = newItAndWasInserted.first;
}

在代码块的末尾,it是一个迭代器,指向刚刚插入的元素。
实际上,在大多数情况下,你可能只想使用yizzlez的建议operator[],但我认为最好注意理论上的最佳答案。

j7dteeu8

j7dteeu84#

它不会覆盖。但是如果你检查返回值,会发现有一个std::pair<iterator, bool>。如果bool为true,那么它被插入了。如果bool为false,那么它因为冲突而没有被插入。此时,你可以通过写迭代器来覆盖数据。

8fsztsew

8fsztsew5#

map.insert()只会在容器中不包含任何元素的情况下插入元素,因此这将忽略后面分配给它的值元素。

相关问题