在map或unordered_map中是否需要insert()
is insert() necessary in a map or unordered_map?
我看到很多通过operator[]
向map
或unordered_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成员函数呢?我想说,对于重叠的功能,绝对没有
- 与C++std::map::insert行为相比,C#排序字典的效率
- std::map insert && hyperload 导致复制
- 为什么在以下示例中 std::map::insert 失败?
- map.insert:"Invalid arguments"错误与 pair<enum,vector<*>>
- 为什么缩小转换范围不能防止错误类型的map.insert()失败
- 当 std::map::insert 找到该元素时,它仍构造该对象的实例.我怎样才能阻止这种情况
- std::map::insert exception
- C++错误: map.insert(make_pair(struct, vector<struct>));
- C++std::map.insert()分段错误
- boost::interprocess::map insert 给出:对重载函数的不明确调用
- 为什么返回map.insert().second会引入无法访问的内存
- 如果map.insert失败,如何在不使用bad_alloc的情况下检查其失败
- 为什么编译顺序在使用 std::map::insert() 时有时会导致分段错误
- std::map.insert "could not deduce template argument for..."
- 如何根据插入对的存在来实现不同的“std::map insert()”行为
- Map::insert不起作用
- Std::map insert()提示位置:c++98和c++11的区别
- 在std::map::insert时出现分段错误
- 何时将node_type与std::map::insert一起使用
- 为什么map.insert()方法调用复制构造函数两次?