My code did the following:
- Retrieve a value from a
mapwithoperator[]. - Check the return value and if
NULLuseinsertto insert a new element in the map.
Magically, an element with value 0 appeared in the map.
After several hours of debugging I discovered the following: map‘s operator[] inserts a new element if the key is not found while insert does not change the value if the key exists.
Even if a default constructor for the map value type does not exist the code compiles and operator[] inserts 0.
Is there a way (e.g. some coding convention I could follow from now on) I could have prevented this from hurting me?
This may sound snarky, but: by reading the documentation.
Since what you did is somewhat expected behaviour of the map, there’s not much you can do to guard against it.
One thing you can heed in the future is the following. In your second step, you did something wrong:
This does never work with C++ standard library functions (other than C compatibility functions and
new): the standard library doesn’t deal in pointers, least of all null pointers, so checking againstNULL(or0ornullptr) rarely makes sense. (Apart from that, it wouldn’t make sense for a map’soperator []to return a pointer in the first place. It obvoiusly returns the element type (or rather, a reference to it)).In fact, the standard library predominantly uses iterators so if at all, check for iterator validity by comparing against the
end()of a container.Unfortunately, your code (checking against
NULL) compiled sinceNULLis actually a macro that’s equal to0in C++ so you can compare it against an integer.C++11 gets safer by introducing the
nullptrkeyword which has a distinct type, so comparing it with an integer wouldn’t compile. So this is a useful coding convention: never useNULL, and instead compile with C++11 support enabled and usenullptr.