在以下示例中,使用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."));
答案 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)
了解insert
和operator[]
您可以实际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
初始化实际项目。请注意,在此期间,可能有一个不同的线程创建项目而不是将其添加到地图中的项目,但它没有真正的区别:它将只创建一次并且没有线程争用。 (这是记录级锁定的实现)。请注意,如果我们使用第一个构造(找到然后插入),我们就无法做到这一点。