Re: Setting an iterator to "end"
Quote:
The bottom line is that using the algorithms is better than writing loops that I've seen too often than not cause all kinds of problems. Even a good coder could botch writing a loop that erases an item but then doesn't increment the iterator incorrectly, or in the wrong place, or whatever. Usage of the proper algorithm removes these problems.
I would say that's true for basic usage, but considering how simple it is to increment correctly, there are so many places where it seems utterly foolish to walk the container twice. After all, the definition of list::remove_if (in MSVC) is merely:
Code:
template<class _Pr1>
void remove_if(_Pr1 _Pred)
{ // erase each element satisfying _Pr1
iterator _Last = end();
for (iterator _First = begin(); _First != _Last; )
if (_Pred(*_First))
_First = erase(_First);
else
++_First;
}
Re: Setting an iterator to "end"
Quote:
Originally Posted by Speedo
I would say that's true for basic usage,
No, for most usage, and I would state for *all* usage involving sequence containers.
Scott Meyer's "Effective STL" lays out the argument for using algorithms over hand-coded loops quite well.
Quote:
but considering how simple it is to increment correctly, there are so many places where it seems utterly foolish to walk the container twice. After all, the definition of list::remove_if (in MSVC) is merely:
My point is that it doesn't matter what the implementation happens to do.
There are other reasons why algorithms are used. The other reasons are (also taken from Scott Meyer's Item 43 in his book) efficiency, maintainability, and correctness.
50 different programmers will write that very same loop 50 different ways. Some of those ways can have bugs, others will increment the iterator differently, etc. This leads to pieces of code written differently that is supposed to accomplish the same thing. Then the maintenance programmer who originally didn't write that code has to figure out exactly what that loop does and if it's doing it correctly. This means more time figuring out what iterator gets invalidated where, etc.
On the other hand, there is only one way to use remove_if() (excepting the way to specify the predicate), and that one way removes all doubts as to what it's supposed to do. The only thing the coder has to check for is if the "true" return value is being used for items that are to be removed. If something needs to be changed (i.e., the correct items are not removed), then the programmer just fixes the predicate. The code to remove_if() remains the same.
Regards,
Paul McKenzie
Re: Setting an iterator to "end"
Quote:
Originally Posted by Graham
break and continue are only marginally less evil than goto. What's wrong with if (!OkToContinue) { ... }? Mind you, in situations like that, I'd start to think about refactoring the loop.
Can you please elaborate? I'm starting to get confused about what your opinion of a well structured loop is...
Re: Setting an iterator to "end"
Quote:
Originally Posted by Hermit
Even this might raise some eyebrows.
IMO, anything other than goto is preferable than changing the loop control variable within the loop.
Taking the example of using erase(), I think one of the bad usages of erase() is exactly as it is being done in a lot of code. Yes, erase() returns an iterator where you can adjust the loop control variable, and you can find a lot of sample code that shows this. But honestly, this breaks all the design principles that I've been taught with respect to for() loops (regardless of the language being used).
That principle is that the control variable should be controlled only by the for loop "auto-increment" mechanism, and not altered within the body of the loop. Too many bugs I've seen is precisely because of this practice of fooling around with the control loop variable, not only in C++, but various other languages where there is a looping mechanism that has a control variable-like syntax.
MyBowlcut's loop could be done using either break, or another bool that controls whether looping should continue, or using find_if() using a predicate. These to me are all preferable than changing control variables within loops. Heck, that is exactly the reason why this thread started -- a bug occurred because of this practice.
Regards,
Paul McKenzie
Re: Setting an iterator to "end"
Quote:
Originally Posted by Graham
break and continue are only marginally less evil than goto.
Indeed! I put a paragraph in our coding standards saying exactly the same thing.