In STL maps, is it better to use map::insert than []?
A while ago, I had a discussion with a colleague about how to insert values in STL maps. I preferred map[key] = value;
because it feels natural and is clear to read whereas he preferred map.insert(std::make_pair(key, value))
.
I just asked him and neither of us can remember the reason why insert is better, but I am sure it was not just a style preference rather there was a technical reason such as efficiency. The SGI STL reference simply says: "Strictly speaking, this member function is unnecessary: it exists only for convenience."
Can anybody tell me that reason, or am I just dreaming that there is one?
When you write
map[key] = value;
there's no way to tell if you replaced the value
for key
, or if you created a new key
with value
.
map::insert()
will only create:
using std::cout; using std::endl;
typedef std::map<int, std::string> MyMap;
MyMap map;
// ...
std::pair<MyMap::iterator, bool> res = map.insert(MyMap::value_type(key,value));
if ( ! res.second ) {
cout << "key " << key << " already exists "
<< " with value " << (res.first)->second << endl;
} else {
cout << "created key " << key << " with value " << value << endl;
}
For most of my apps, I usually don't care if I'm creating or replacing, so I use the easier to read map[key] = value
.
The two have different semantics when it comes to the key already existing in the map. So they aren't really directly comparable.
But the operator[] version requires default constructing the value, and then assigning, so if this is more expensive then copy construction, then it will be more expensive. Sometimes default construction doesn't make sense, and then it would be impossible to use the operator[] version.
Another thing to note with std::map
:
myMap[nonExistingKey];
will create a new entry in the map, keyed to nonExistingKey
initialized to a default value.
This scared the hell out of me the first time I saw it (while banging my head against a nastly legacy bug). Wouldn't have expected it. To me, that looks like a get operation, and I didn't expect the "side-effect." Prefer map.find()
when getting from your map.
If the performance hit of the default constructor isn't an issue, the please, for the love of god, go with the more readable version.
:)