What are the common misuse of using STL containers with iterators?
Forgetting that iterators are quite often invalidated if you change the container by inserting or erasing container members.
For many great tips on using STL I highly recommend Scott Meyers's book "Effective STL" (sanitised Amazon link)
The end range check should be using != and not < since the order of the pointers isn't guaranteed.
Example:
for(it = list.begin(); it != list.end(); ++it)
{
// do stuff
}
Using them without reading the "Effective STL" book by Scott Meyers. :) Really. This makes most of the stupid bugs go away.
A few others:
Converting a reverse iterator to a base iterator without remembering that the iterator will now be one element beyond the one it was pointing to.
Trying to use algorithms that require a random-access iterator with iterators of things like sets and maps.
Editing the key of a map entry with a non-const iterator (this happens to build on VS.Net, but won't with GCC)
Proper continuation after erase()
.
Assuming:
Container::iterator i = cont.begin(), iEnd = cont.end();
For instance on std::map
, this is not a good idea:
for (; i != iEnd; ++i) {
if (i->second.eraseCondition()) {
cont.erase(i);
}
}
This would work:
for (; i != iEnd; ) {
Container::iterator temp = i;
++temp;
if (i->second.eraseCondition()) {
cont.erase(i);
}
i = temp;
}
And this also:
for (; i != iEnd; ) {
if (i->second.eraseCondition()) {
cont.erase(i++);
}
else {
++i;
}
}
It's been too many times really that I've had to apply these fixes in some production code :(
Using an auto_ptr inside a container, e.g.
list<auto_ptr<int> > foo;
Fortunately, a lot of auto_ptr implementations these days are written to make this impossible.
This isn't only problem with STL containers - modyfing container when iterating over it almost always leads to problems.
This is very common source of bugs in games - most game loops consists of iterating over each game object doing something. f this something adds or erases elements from game objects container there is almost surelly bug.
Solution - have two containers - objectsToDelete and objectsToAdd - in game code add objects to that containers, and update game objects container only after you iterated over it.
objetsToAdd can be Set to ensure we wont delete anything more than one time.
objectsToDelete can be Queue if you can construct Object without adding it to game objects container, or it can be some other class (ObjectCreateCommand?) if your code assumes that Object instance is always added to game objects container directly after creation (for example in constructor).
list<int> l1, l2;
// ...
for_each(l1.begin(), l2.end(), do_it());