使用std :: map.insert(“xyz”)或只是map [ind] =“xyz”时使用insert函数有什么区别

时间:2011-02-08 14:35:28

标签: c++ arrays stl map insert

在以下示例中,使用1)与2)的优缺点是什么。是否存在任何内存分配优势,以及没有空间不足的任何好处?

map <  int, string> Employees;  



  // 1) Assignment using array index notation  

   Employees[5234] = "Mike C.";  

  // 2) Assignment using member function insert() and STL pair  

    Employees.insert(std::pair<int, * char>(1923,"David D."));  

5 个答案:

答案 0 :(得分:5)

第一个用键5234创建一个映射,并返回对那里保存的字符串的引用,“Mike C”被分配给它 - 重要的一点是,如果该键已经存在,这将覆盖该键的值(因为返回了对值的引用)。

第二种方法检查密钥是否存在,如果密钥已存在则不会覆盖。

对于内存分配,如果映射不存在,两者都会将地图大小增加1。以上是两种方法AFAIK之间的唯一区别。

答案 1 :(得分:4)

这里的区别在于选项1将在所有情况下将值赋给键,其中选项2可以返回包含项的迭代器的std :: pair,以及插入成功的布尔通知。这意味着如果您的地图中已存在项目1923,则插入功能将返回<iterator, false>,通知您该地图中已存在该密钥,而不会覆盖该地址。

std::map<int, char*> aMap;
aMap[12] = "An Entry";

std::pair< std::map<int, char*>::iterator, bool > result;
result = aMap.insert(12, "A new entry");

//now result.first points to the existing entry at 12, result.second == false

我能想到的唯一性能优势是,在执行插入操作之前,您没有执行if(aMap.count(12) == 0)if(aMap.find(12) == aMap.end()),从而节省了处理时间。

答案 2 :(得分:4)

  • 如果地图中存在key ,则Employees[key] = value 会向地图添加新的键值对。

  • 如果key已经存在,那么Employees[key] = value只需使用给定密钥更新值。

  • Employees.insert()始终将新的键值对添加到地图。但是,如果密钥已存在,则不执行任何操作。如果您希望允许不同的元素具有相同的键,则可以使用multimap

答案 3 :(得分:1)

您可以在Scott Meyers的“Effective STL”一书中详细阅读(主题24)。

答案 4 :(得分:1)

了解insertoperator[]

之间的差异非常有用

您可以实际operator[]实施insert,因为它会返回pair<iterator,bool>

因此,人们可以(并且可能会)实施:

Value& map<K,T>::operator[]( const Key& key )
{
   return insert( make_pair(key, Value()) ).first->second;
}

使用中的实际应用: 在典型的“延迟加载”缓存情况下,您可能有map<Key, shared_ptr<Value> >

程序员通常会以find开头:

  const_iterator iter = theMap.find(key);
  if( iter!= theMap.end())
     return iter->second;
  else
  {
    // create the item then insert it
  }

更好的方法是:

shared_ptr<Value> value = theMap[key];
if( !value )
{
   value.reset( /*load logic */ )
}
return value;

在上面的多线程情况下,使用实现“boost :: once”逻辑的包装类而不是shared_ptr。假设加载对象需要很长时间。在经典案例中,您可能会在查找项目时锁定整个地图,然后创建它。所以没有其他线程可以使用地图。

相反,我们现在仅为查找锁定映射并以“ONCE_INIT”状态创建对象。然后我们解锁地图并使用boost::call_once初始化实际项目。请注意,在此期间,可能有一个不同的线程创建项目而不是将其添加到地图中的项目,但它没有真正的区别:它将只创建一次并且没有线程争用。 (这是记录级锁定的实现)。请注意,如果我们使用第一个构造(找到然后插入),我们就无法做到这一点。