I was about to write code like this:
std::list<whatevertype> mylist;
// ...
std::list<whatevertype>::iterator it;
for(it = mylist.begin(); it != mylist.end(); ++it) {
// ...
if(some condition)
mylist.erase(it);
}
But I realized, this code is wrong: mylist.erase(x)
will invalidate the iterator it
, so the ++it
is likely to fail.
So I tried changing it to
std::list<whatevertype>::iterator it;
std::list<whatevertype>::iterator nextit;
for(it = mylist.begin(); it != mylist.end(); it = nextit) {
// ...
nextit = it + 1;
if(some condition)
mylist.erase(it);
}
But, to my surprise, this failed: evidently operator+
is not defined for std::list
iterators.
I've since found this other question and learned that the standard idiom for deleting "out from under" an iterator is more like
for(it = mylist.begin(); it != mylist.end(); ) {
if(some condition)
it = mylist.erase(it);
else ++it;
}
I believe I could also get away with
for(it = mylist.begin(); it != mylist.end(); ) {
// ...
std::list<whatevertype>::iterator previt = it;
++it;
if(some condition)
mylist.erase(previt);
}
But my question is, is there a reason that operator+
is not defined for these iterators?
One rule they had with the std iterators and collection was to make expensive things verbose.
On a list iterator, it+50
takes O(50) time. On a vector iterator, it+50
takes O(1) time. So they implemented +
on vector iterators (and other random access iterators) but not on list iterators (and other weaker iterators).
std::next
and std::advance
and std::prev
can solve your problem easier:
auto previt = std::prev(it);
or
auto nextit = std::next(it);
these also take a count, but because they are an explicit function call it was decided that them being expensive is acceptable.
Among other things, you can search for calls to std::next
and std::prev
and get iterator manipulation; +
is heavily overloaded and finding the expensive calls is hard.
Note that std::basic_string
doesn't follow the same conventions as other std
containers.