在map或unordered_map中是否需要insert()

is insert() necessary in a map or unordered_map?

本文关键字:map insert unordered 是否      更新时间:2023-10-16

我看到很多通过operator[]mapunordered_map添加项目的例子,如:

int main() {
    unordered_map <string, int> m;
    m["foo"] = 42;
    cout << m["foo"] << endl;
}

是否有理由使用insert成员函数来代替?看起来它们的作用是一样的

它们不是。

operator[]将覆盖这个键的值,如果它存在,而insert不会。

如果使用operator[]插入元素,预计会慢一点(详见下面@MatthieuM的评论),但这在这里并不重要。

std::map::insert返回std::pair< iterator, bool >,其中.second将告诉您值是否已插入或已存在。


关于你的评论:你不能有2个元素具有相同的键和不同的值。这不是multimap

如果映射中存在一个元素,且该元素与你要插入的键相同,则:

  • operator[]将覆盖现有值
  • std::map::insert将不做任何事情。*返回一个std::pair< iterator, bool >,其中.second将是false(表示"新元素没有插入,因为这样的键已经存在"),.first将指向找到的元素。

*我改变了这一点,感谢@luk32给出的注释/注释;但是我写的"will not do anything"并不是字面上的意思,我的意思是它不会改变现有元素

的值

使用insert()可以帮助在某些情况下提高性能(更具体地说,对于std::map,因为搜索时间是O(log(n))而不是常数平摊)。以以下常见示例为例:

std::map<int, int> stuff;
// stuff is populated, possibly large:
auto iterator = stuff.find(27);
if(stuff.end() != iterator)
{
   // subsequent "find", set to 15
   iterator->second = 15;
}
else
{
   // insert with value of 10
   stuff[27] = 10;
}

上面的代码有效地找到了元素两次。我们可以这样写(稍微)更有效率:

// try to insert 27 -> 10
auto result = stuff.insert(std::make_pair(27, 10));
// already existed
if(false == result.second)
{
   // update to 15, already exists
   result.first->second = 15;
}

上面的代码只尝试查找一个元素一次,降低了算法的复杂度。对于频繁的操作,这可以极大地提高性能。

两者不相等。insert不会覆盖一个已经存在的值,它返回一个pair<iterator, bool>,其中iterator是键的位置,不管它是否已经存在。bool表示插入是否发生。

operator[]有效地在键上执行lower_bound。如果该操作的结果是具有相同键的iterator,则返回对该值的引用。如果没有,则插入一个带有默认构造值的新节点,然后返回对该值的引用。这就是为什么operator[]是一个非const成员——如果键值不存在,它会自动激活键值。

如果值类型的构造成本很高,这可能会影响性能。

还请注意,在c++ 11中,我们有一个emplace方法,它的工作原理与insert几乎相同,除了它在发生插入时根据转发的参数就地构造键值对。

我在某种程度上不同意Kiril的答案,我认为它不充分,所以我给出了我的答案。

根据cppreference, std::map::operator[]相当于某个insert()调用。我也认为他说价值将被覆盖是错误的。它说:"返回值如果不存在键key的元素,则引用新元素的映射值。否则将返回对现有元素的映射值的引用。"

所以它似乎是一个方便的包装。然而,insert()具有重载的优点,因此它在一个名称下提供了更多的功能。

我给Kiril一点,乍一看他们似乎有一点不同的功能,但是我认为他提供的例子并不等同于彼此。

因此,作为使用insert的一个例子/理由,我要指出,一次插入多个元素,或者使用hint(在这里调用3-6)。

那么在map或unordered_map中是否需要insert() ?我会说是的。此外,operator[]是不必要的,因为它可以使用insert来模拟/实现,而其他方式是不可能的!它只是提供了更多的功能。然而,写像(insert(std::make_pair(key, T())).first)->second)(在cppreference之后)这样的东西似乎比[]更麻烦。

那么,是否有理由使用insert成员函数呢?我想说,对于重叠的功能,绝对没有