Очень полезно знать эту разницу между 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;
В многопоточной ситуации, описанной выше, вместо shared_ptr использовать класс-оболочку, который реализует "boost ::однажды "логика"Допустим, загрузка объекта занимает много времени.В классическом случае вы, вероятно, заблокируете всю карту, пока будете искать элемент и затем создавать его.Так что никакой другой поток не может использовать карту вообще.
Вместо этого мы теперь блокируем карту только для поиска и создаем объект в его состоянии "ONCE_INIT".Затем мы разблокируем карту и используем boost::call_once
для инициализации фактического элемента.Обратите внимание, что в течение этого времени возможно, что элемент был создан другим потоком, а не тем, который добавил его на карту, но это не имеет особого значения: он будет создан ровно один раз, и в этом нет конфликта потоков.(Это реализация блокировки на уровне записей).Обратите внимание, что если бы мы использовали первую конструкцию (find, insert), мы бы не смогли этого сделать.