It is very useful to know this difference between insert and operator[]
In fact, you can implement operator[] in terms of insert , since it returns pair<iterator,bool>
Thus, it is possible (and possibly) to implement:
Value& map<K,T>::operator[]( const Key& key ) { return insert( make_pair(key, Value()) ).first->second; }
Practical application: In a typical situation with "lazy loading" you may have map<Key, shared_ptr<Value> >
Typically, a programmer begins with a search:
const_iterator iter = theMap.find(key); if( iter!= theMap.end()) return iter->second; else {
The best approach:
shared_ptr<Value> value = theMap[key]; if( !value ) { value.reset( ) } return value;
In the multi-threaded situation above, instead of shared_ptr, use a wrapper class that implements the logic "boost :: once". Let's say that loading an object takes a lot of time. In the classic case, you are likely to block the entire map while you search for the item, and then create it. Thus, no other thread can use the card at all.
Instead, we now block the map for search only and create an object in the "ONCE_INIT" state. Then we unlock the card and use boost::call_once to initialize the actual item. Please note that during this time it is possible that another thread created an element different from the one that added it to the map, but this does not matter: it will be created exactly once, and there is no thread conflict. (This is a write-level lock implementation). Note that if we used the first construct (find then insert), we would not be able to do this.