前段时间,我和同事讨论了如何在STL映射中插入值。I prefer map[key] = value;因为它让人感觉自然,读起来清晰,而他更喜欢地图。插入(std:: make_pair(关键字,值))。

我只是问了他,我们都不记得为什么插入更好,但我相信这不仅仅是一个风格偏好,而是有一个技术原因,如效率。SGI STL引用简单地说:“严格地说,这个成员函数是不必要的:它只是为了方便而存在。”

有人能告诉我原因吗,还是我只是在做梦?


当前回答

从异常安全的角度来看,Insert更好。

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

Map [key] -创建一个默认值的Map元素。 = value—将值复制到该元素中。

第二步可能发生异常。因此,该操作将只完成部分(一个新元素被添加到map中,但该元素没有初始化值)。当一个操作没有完成,但系统状态被修改时,这种情况被称为有“副作用”的操作。

插入操作提供了强有力的保证,意味着它没有副作用(https://en.wikipedia.org/wiki/Exception_safety)。插入要么完全完成,要么使映射处于未修改状态。

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

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

其他回答

map::insert()的一个问题是,如果键已经存在于映射中,它不会替换某个值。我见过Java程序员编写的c++代码,他们希望insert()的行为与Java中的Map.put()相同,其中值被替换。

下面是另一个例子,如果键值存在,操作符[]会覆盖键值,但是.insert不会覆盖键值。

void mapTest()
{
  map<int,float> m;


  for( int i = 0 ; i  <=  2 ; i++ )
  {
    pair<map<int,float>::iterator,bool> result = m.insert( make_pair( 5, (float)i ) ) ;

    if( result.second )
      printf( "%d=>value %f successfully inserted as brand new value\n", result.first->first, result.first->second ) ;
    else
      printf( "! The map already contained %d=>value %f, nothing changed\n", result.first->first, result.first->second ) ;
  }

  puts( "All map values:" ) ;
  for( map<int,float>::iterator iter = m.begin() ; iter !=m.end() ; ++iter )
    printf( "%d=>%f\n", iter->first, iter->second ) ;

  /// now watch this.. 
  m[5]=900.f ; //using operator[] OVERWRITES map values
  puts( "All map values:" ) ;
  for( map<int,float>::iterator iter = m.begin() ; iter !=m.end() ; ++iter )
    printf( "%d=>%f\n", iter->first, iter->second ) ;

}

如果默认构造函数的性能影响不是问题,看在上帝的份上,请使用可读性更好的版本。

:)

从异常安全的角度来看,Insert更好。

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

Map [key] -创建一个默认值的Map元素。 = value—将值复制到该元素中。

第二步可能发生异常。因此,该操作将只完成部分(一个新元素被添加到map中,但该元素没有初始化值)。当一个操作没有完成,但系统状态被修改时,这种情况被称为有“副作用”的操作。

插入操作提供了强有力的保证,意味着它没有副作用(https://en.wikipedia.org/wiki/Exception_safety)。插入要么完全完成,要么使映射处于未修改状态。

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

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

当涉及到映射中已经存在的键时,两者具有不同的语义。所以它们没有直接的可比性。

但是操作符[]版本需要默认构造值,然后赋值,所以如果这比复制构造更昂贵,那么它也会更昂贵。有时默认结构没有意义,那么就不可能使用操作符[]版本。