Why does std::map operator[] create an object if the key doesn't exist?
Because operator[]
returns a reference to the value itself and so the only way to indicate a problem would be to throw an exception (and in general, the STL rarely throws exceptions).
If you don't like this behavior, you can use map::find
instead. It returns an iterator instead of the value. This allows it to return a special iterator when the value is not found (it returns map::end
) but also requires you to dereference the iterator to get at the value.
Standard says (23.3.1.2/1) that operator[] returns (*((insert(make_pair(x, T()))).first)).second
. That's the reason. It returns reference T&
. There is no way to return invalid reference. And it returns reference because it is very convenient I guess, isn't it?
To answer your real question: there's no convincing explanation as to why it was done that way. "Just because".
Since std::map
is an associative container, there's no clear pre-defined range of keys that must exist (or not exist) in the map (as opposed to the completely different situation with std::vector
). That means that with std::map
, you need both non-insering and inserting lookup functionality. One could overload []
in non-inserting way and provide a function for insertion. Or one could do the other way around: overload []
as an inserting operator and provide a function for non-inserting search. So, someone sometime decided to follow the latter approach. That's all there's to it.
If they did it the other way around, maybe today someone would be asking here the reverse version of your question.
Its is for assignment purposes:
void test()
{
std::map<std::string, int >myMap;
myMap["hello"] = 5;
}
I think it's mostly because in the case of map (unlike vector, for example) it's fairly cheap and easy to do -- you only have to create a single element. In the case of vector they could extend the vector to make a new subscript valid -- but if your new subscript is well beyond what's already there, adding all the elements up to that point may be fairly expensive. When you extend a vector you also normally specify the values of the new elements to be added (though often with a default value). In this case, there would be no way to specify the values of the elements in the space between the existing elements and the new one.
There's also a fundamental difference in how a map is typically used. With a vector, there's usually a clear delineation between things that add to a vector, and things that work with what's already in the vector. With a map, that's much less true -- it's much more common to see code that manipulates the item that's there if there is one, or adds a new item if it's not already there. The design of operator[] for each reflects that.