当前位置:  开发笔记 > 编程语言 > 正文

在STL映射中,使用map :: insert比[]更好吗?

如何解决《在STL映射中,使用map::insert比[]更好吗?》经验,为你挑选了8个好方法。

不久前,我与一位同事讨论了如何在STL 地图中插入值.我更喜欢 map[key] = value; 因为它感觉自然而且阅读清晰,而他更喜欢 map.insert(std::make_pair(key, value))

我刚刚问他,我们都不记得插入更好的原因,但我确信这不仅仅是一种风格偏好,而是有一个技术原因,如效率.在SGI STL参考只是说"严格地说,这个成员函数是不必要的:它的存在只是为了方便."

任何人都可以告诉我这个理由,还是我只是梦想有一个?



1> netjeff..:

当你写作

map[key] = value;

没有办法告诉你是否更换valuefor key,或者你是否创建了一个新keyvalue.

map::insert() 只会创建:

using std::cout; using std::endl;
typedef std::map MyMap;
MyMap map;
// ...
std::pair res = map.insert(MyMap::value_type(key,value));
if ( ! res.second ) {
    cout << "key " <<  key << " already exists "
         << " with value " << (res.first)->second << endl;
} else {
    cout << "created key " << key << " with value " << value << endl;
}

对于我的大多数应用程序,我通常不关心我是否正在创建或替换,因此我使用更容易阅读map[key] = value.


应该注意的是map :: insert永远不会替换值.在一般情况下,我会说在第二种情况下最好使用`(res.first) - > second`而不是`value`.

2> Greg Rogers..:

当涉及到地图中已存在的密钥时,这两者具有不同的语义.所以它们并不是真正可比的.

但是operator []版本需要默认构造值,然后分配,所以如果这更昂贵然后复制构造,那么它将更昂贵.有时默认构造没有意义,然后就不可能使用operator []版本.



3> Hawkeye Park..:

另外需要注意的是std::map:

myMap[nonExistingKey];将在地图中创建一个新条目,键入nonExistingKey初始化为默认值.

当我第一次看到它时,这让我感到很害怕(同时我的头撞在了一个非常遗留的小虫身上).不会期待它.对我来说,这看起来像一个获取操作,我没想到"副作用".不想map.find()从你的地图时获得.


这是一个不错的观点,虽然哈希映射对于这种格式非常普遍.它可能是那些"没有人认为奇怪的奇怪"之一,仅仅因为他们使用相同的惯例有多么广泛

4> Torlack..:

如果默认构造函数的性能不是问题,那么对于上帝的爱,请使用更易读的版本.

:)


正如格雷格·罗杰斯(Greg Rogers)写道:"当涉及地图中已存在的密钥时,两者的语义不同.所以它们并不是真正直接可比的."
第二!要记住这一点.太多的人为了纳秒加速而牺牲了钝性.怜悯那些必须保持这种暴行的可怜的灵魂!

5> anton_rh..:

insert 从异常安全的角度来看更好.

表达式map[key] = value实际上是两个操作:

    map[key] - 使用默认值创建地图元素.

    = value - 将值复制到该元素中.

第二步可能会发生异常.结果,操作将仅部分完成(在元素中添加了一个新元素,但该元素未初始化value).操作未完成但系统状态被修改的情况称为具有"副作用"的操作.

insert操作提供了强有力的保证,意味着它没有副作用(https://en.wikipedia.org/wiki/Exception_safety).insert要么已完全完成,要么将地图保留为未修改状态.

http://www.cplusplus.com/reference/map/map/insert/:

如果要插入单个元素,则在异常情况下容器中没有更改(强保证).



6> Rampal Chaud..:

如果您的应用程序速度很快,我将建议使用[]运算符,因为它创建了原始对象的总共3个副本,其中2个是临时对象,并且迟早会被销毁.

但是在insert()中,创建了4个原始对象的副本,其中3个是临时对象(不一定是"临时对象")并被销毁.

这意味着额外的时间:1.一个对象内存分配2.一个额外的构造函数调用3.一个额外的析构函数调用4.一个对象内存释放

如果你的对象很大,构造函数是典型的,析构函数可以释放大量的资源,上面的点数更多.关于可读性,我认为两者都是公平的.

同样的问题进入我的脑海,但不是可读性而是速度.这是一个示例代码,通过它我了解了我提到的这一点.

class Sample
{
    static int _noOfObjects;

    int _objectNo;
public:
    Sample() :
        _objectNo( _noOfObjects++ )
    {
        std::cout<<"Inside default constructor of object "<<_objectNo< map;

    map.insert( std::make_pair( 1, sample) );
    //map[1] = sample;
    return 0;
}

使用insert()时的输出 使用[]运算符时的输出


现在再次运行该测试并启用完全优化.
另外,考虑一下operator []实际上做了什么.它首先在地图中搜索与指定键匹配的条目.如果找到一个,则用指定的值覆盖该条目的值.如果没有,则插入具有指定键和值的新条目.地图越大,运算符[]搜索地图的时间就越长.在某些时候,这将弥补额外的复制c'tor调用(如果在编译器完成其优化魔术后它甚至停留在最终程序中).

7> GutiMac..:

现在在c ++ 11中我认为在STL映射中插入一对的最佳方法是:

typedef std::map MyMap;
MyMap map;

auto& result = map.emplace(3,"Hello");

结果将是具有一对:

第一个元素(result.first)指向插入的对,或者如果该键已存在则指向该键.

第二个元素(result.second),如果插入正确或为假,则出现错误.

PS:如果您不了解订单,可以使用std :: unordered_map;)

谢谢!



8> Anthony Cram..:

map :: insert()的问题在于,如果密钥已经存在于地图中,它将不会替换值.我见过Java程序员编写的C++代码,他们希望insert()的行为与Java中的Map.put()相同,其中值被替换.

推荐阅读
Chloemw
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有