STL映射插入效率:[] vs. insert

| 映射插入有两种方法:
m[key] = val;
要么
m.insert(make_pair(key, val));
我的问题是,哪个操作更快? 人们通常说第一个比较慢,因为如果地图中不存在“键”,则STL标准首先“插入”默认元素,然后将“ val”分配给默认元素。 但是我看不出第二种方法会更好,因为\'make_pair \'。与
pair<T1, T2>(key, val)
相比,make_pair实际上是制作\'pair \'的便捷方法。无论如何,他们两个都执行两个分配,一个是将\'key \'分配给\'pair.first \',而两个是将\'val \'分配给\'pair.second \'。配对后,map插入由\'pair.second \'初始化的元素。 所以第一种方法是1. \'
default construct of typeof(val)
\'2.赋值 第二种方式是1.分配2. \'
copy construct of typeof(val)
\'     
已邀请:
两者都完成不同的事情。
m[key] = val;
如果
key
不存在,则将插入一个新的键-值对,否则将覆盖映射到
key
的旧值。
m.insert(make_pair(key, val));
仅当ѭ6不存在时才插入该对,它将永远不会覆盖旧值。因此,根据要完成的任务进行选择。 对于这个问题,更有效的是:配置文件。 :P也许是我要说的第一种方法。两种方式都是这种情况(又称副本),因此唯一的区别在于构造。众所周知并且应该实现,默认构造基本上应该是无操作的,因此非常有效。副本就是那个副本。因此,以一种方式我们得到一个“无操作”和一个副本,以一种方式我们得到两个副本。 编辑:最后,相信您的配置文件告诉您什么。我的分析不像@Matthieu在其评论中提到的那样,但这是我的猜测。 :) 然后,我们有了C ++ 0x,第二种方式的双份副本将一无所获,因为现在可以轻松移动它们。因此,最后,我认为这取决于我的第一点:使用正确的方法来完成您想做的事情。     
在具有大量内存的轻负载系统上,此代码:
#include <map>
#include <iostream>
#include <ctime>
#include <string>

using namespace std;

typedef map <unsigned int,string> MapType;
const unsigned int NINSERTS = 1000000;

int main() {
    MapType m1;
    string s = \"foobar\";
    clock_t t = clock();
    for ( unsigned int i = 0; i < NINSERTS; i++ ) {
        m1[i] = s;
    }
    cout << clock() - t << endl;
    MapType m2;
    t = clock();
    for ( unsigned int i = 0; i < NINSERTS; i++ ) {
        m2.insert( make_pair( i, s ) );
    }
    cout << clock() - t << endl;
}
产生:
1547
1453
或重复运行时具有相似的值。因此,在这种情况下,insert快一些。     
性能方面,我认为它们总体上大致相同。具有大对象的地图可能会有一些例外,在这种情况下,您应该使用[]或Emplace来创建比\'insert \'更少的临时对象。有关详细信息,请参见此处的讨论。 但是,如果在插入运算符上使用\'hint \'函数,则在特殊情况下可能会导致性能提高。因此,从这里查看选项2:
iterator insert (const_iterator position, const value_type& val);
如果您给出了很好的提示(通常情况是您知道要在地图的后面添加内容),则可以将'​​insert \'操作减少到固定时间(从log(n)开始)。     
我们必须提到相对性能取决于要复制的对象的类型(大小),以完善分析。 我对(int-> set)的映射进行了类似的实验(至nbt)。我知道这是一件很糟糕的事情,但是可以说明这种情况。 \“ value \”,在这种情况下是一组整数,其中有20个元素。 我执行[] = Vs的一百万次迭代。插入操作并执行RDTSC / iter-count。 [] =设置| 10731个周期 insert(make_pair <>)| 26100个循环 它显示了由于复制而增加的罚款额度。当然,CPP11(移动ctor)  将改变图片。     
我对此: 值得提醒的是,映射是平衡的二叉树,大多数修改和检查都采用O(logN)。 确实取决于您要解决的问题。 1)如果您只想插入一个不存在的值, 然后[]会做两件事: a)检查物品是否存在 b)如果不存在,将创建对并执行插入操作(    O(logN)的双重工作,所以我将使用insert。 2)如果不确定是否存在,则通过以下几行类似if(map.find(item)== mp.end())的方法检查项目是否存在在某处,然后使用insert,因为双重工作[]会执行b)如果您没有检查,则取决于,导致insert不会修改该值(如果存在),否则将等于     
我的答案不是效率,而是安全,这与选择插入算法有关: ѭ13和ѭ14调用将触发元素的析构函数。如果您的析构函数内部有严重行为,则这可能会带来危险的副作用。 发生这种危险之后,我不再依赖STL的隐式惰性插入功能,并始终使用显式检查对象是否在其ctor / dtor中具有行为。 看到这个问题: 将对象添加到std :: list时,析构函数调用对象     

要回复问题请先登录注册