C++ 在映射或无序映射中需要insert()吗?

C++ 在映射或无序映射中需要insert()吗?,c++,C++,我看到许多示例通过操作符[]将项目添加到映射或无序映射,如下所示: int main() { unordered_map <string, int> m; m["foo"] = 42; cout << m["foo"] << endl; } intmain(){ 无序地图m; m[“foo”]=42; 不能他们不是 operator[]将覆盖此键的值(如果存在),而insert将不覆盖 如果使用operator[]插入元素,则预计会稍

我看到许多示例通过
操作符[]
将项目添加到
映射
无序映射
,如下所示:

int main() {
    unordered_map <string, int> m;
    m["foo"] = 42;
    cout << m["foo"] << endl;
}
intmain(){
无序地图m;
m[“foo”]=42;
不能他们不是

operator[]
将覆盖此键的值(如果存在),而
insert
将不覆盖

如果使用
operator[]
插入元素,则预计会稍微慢一点(有关详细信息,请参见下面的@MatthieuM注释),但这在这里并不重要

std::map::insert
返回
std::pair
,其中
.second
将告诉您该值是插入的还是已经存在


关于您的评论:您不能有两个具有相同键和不同值的元素。这不是一个
多重映射

如果地图中有一个元素与您尝试插入的键相同,则:

  • 运算符[]
    将覆盖现有值
  • std::map::insert
    不会做任何事情。*返回一个
    std::pair
    ,其中
    第二个
    将是
    false
    (表示“新元素未插入,因为这样的键已经存在”),而
    。第一个
    将指向找到的元素

*感谢@luk32给出的注释/备注,我改变了这一点;但通过写“不会做任何事情”,我并不是字面意思,我的意思是它不会改变现有元素的值,我在一定程度上不同意Kiril的答案,我认为它不完整,所以我给出了我的答案

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

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

我向Kiril指出,乍一看,它们的功能似乎有点不同,但他提供的示例并不完全相同

因此,作为使用
insert
的示例/理由,我要指出,一次插入许多元素,或者使用
hint
(调用中的3-6)

那么,在映射或无序映射中是否需要insert()呢? 我会说是的。此外,没有必要使用
操作符[]
,因为它可以使用
insert
来模拟/实现,而另一种方法是不可能的!它只是提供了更多的功能。但是,编写类似
(insert(std::make_pair(key,T())。首先)->其次)
(之后)的东西似乎比
[/code>更麻烦

因此,是否有理由改用插入成员函数? 我想说的是,对于重叠功能,绝对不是。

使用
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;
}

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

这两个元素并不等效。
insert
不会覆盖现有值,它返回一个
对,其中
迭代器
是密钥的位置,regardles它是否已经存在。布尔值指示插入是否发生

操作符[]
有效地对键执行
下限
。如果该操作的结果是具有相同键的
迭代器
,则返回对该值的引用。如果不是,则插入具有默认构造值的新节点,然后返回对该值的引用。这就是为什么
操作符[]
是一个非常量成员-如果键值不存在,它会自动激活该键值。如果值类型的构造成本很高,这可能会影响性能。


还要注意的是,在C++11中,我们有一个
emplace
方法,其工作原理与
insert
几乎相同,只是如果发生insert,它会根据转发的参数构造键值对。

Ok,那么如果插入两个具有相同键值的项会发生什么情况呢?该键值的数据不会被覆盖。括号表示法为eqivalent to
(*((m.insert(value\u type(k,data\u type()))).first)).second=data;
(借用脚注3)。也就是说,它插入带有默认构造数据的键,然后获取返回的迭代器(the
。first
),它要么指向旧的、未修改的键值对(如果存在),要么指向刚添加的新键值对,并将与该键值关联的数据(第二个
)设置为所需的值。
操作符[]
也不会做任何事情。
T::operator=
使用从
map::operator[]获得的引用
可以。您可以使用
insert()获得相同的引用
。这取决于严格的语义分析。但我认为我就在这里,虽然我仍然理解你更人性化的方法,但它们的行为似乎有所不同。但当你分解代码时,它们就不是了。只是这里发生了更多的事
mymap[“答案”]=42
比看起来的要慢。至少在我看来。@KirilKirov:
操作符[]
预计会慢一点,但我不会说这是因为检查;
操作符[]
插入
执行相同数量的检查。
操作符[]
对于直接插入速度较慢,因为它首先生成默认值
// 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;
}