In C++ Primer 4th, sec 3.3.2, it states that C++ programmers use !=
rather than < in a for loop.
Not smart programmers, who understand what it means for a loop guard
test to check for the correct precondition.
Fact is, if there is some loop variable i, and a limiting value N, and
if it is incorrect to execute the loop body if i is equal to N, or if i
is greater than N, then the proper guard for executing that loop body
is (i < N).
The test (i != N) only works when other logic has already ensured that
(i <= N) is true. That other logic is usually the fact N is
nonnegative, and that i starts at value 0 (and so i <= N) is initially
true, and that i increments by one in each loop iteration toward the
limiting value, and that N does not change.
The correct test (i < N) doesn't rely on any such assumptions. It
doesn't matter what happens to the value of i in each iteration.
The following small snippet erases punctuations in a string. It works
well with < used in the for loop but it breaks when != is used instead.
That's because the body of the loop changes N. If N is a moving target,
then the invariant (i <= N) does not hold from one iteration to the
next. On one iteration, it could be that i == N - 1. But then, i
increments, and N decrements, so that i is suddenly N + 1.
#include <string>
#include <iostream>
#include <exception>
#include <cctype>
using namespace std;
int main(){
string s = "hello, world!";//s: i18n
//for (string::size_type sz = 0; sz < s.size(); ++sz){
/*works with < */
for (string::size_type sz = 0; sz != s.size(); ++sz){
/*doesn't work with != */
try{
if (ispunct(s.at(sz))){
s.erase(sz, 1);
}
You have another bug here anyway, because if you erase an element of
the string, then you must not increment the sz index. By doing that,
you skip a character, which could be a punctuation character.
Imagine that the action of erase is like that of the Del key on your
keyboard in a typical text editor. When you use Del, the character
under the cursor is eaten, and everything after it moves one position
to the left. If you wanted to delete several punctuation characters in
a row, you'd type Del several times without having to move the cursor.
Similarly, the zs ``cursor'' must not move while characters are being
deleted; after each erasure, the next character to be processed shifts
into the current position, and so that position of the string must be
reevaluated.
If that logic is corrected, then the != test will work, since in any
given iteration, only the s.size() value or the sz value will change,
not both at the same time. Either the size decrements by one, bringing
it closer to sz, or sz increments by one closer to s.size().