Hot on the tails of my
previous woe with C++ std::map I've just discovered another issue the hard way.
typedef std::map map_t;
map_t::iterator i;
Thus much is uncontroversially legal and commonplace. But what is one now allowed to do with i? Obviously, ++i, *i and similar are an appalling idea, but what about map_t::iterator j==i; or bool isNull(map_t::iterator j) { return i==j; } ?
Much to my surprise and discomfort it turns out both the latter two examples are illegal: the only thing one may do with a default-constructed iterator is assign a well-defined iterator into it. That I've managed to code in C++ for twelve years and not find this out sooner just goes to show how hairy and dangerous C++ is around the edges.
In practice, the GNU libstdc++ copes fine with assignments and comparisons of default-constructed iterators (with the small caveat that a default-constructed iterator is not guaranteed distinct from any other - std::vector().begin() looks like a default-constructed iterator, for example). Microsoft Visual C++, on the other hand, throws a sizeable wobbler.
Drat.
There is, of course, map.end() - a well-defined special iterator value for any given map. I would be using it, but for two exasperating issues:
- For (i==map.end()) you have to have the map in hand.
- Although I believe in practice it's utterly fine for my purposes, (i==map.end()) isn't thread-safe.
On Monday, I fear I need to do a merry dance. In some cases I use map.end() and make sure I have a mutex lock; in others I resort to boost::optional.
(I also considered using map_t::value_type *, but you can't map.erase() that. Argh!)