I am a self-taught programmer. I started programming about 1.5 years ago. Now I have started to have programming classes in school. We have had programming classes for 1/2 year and will have another 1/2 right now.
In the classes we are learning to program in C++ (which is a language that I already knew to use quite well before we started).
I have not had any difficulties during this class but there is one recurring problem that I have not been able to find a clear solution to.
The problem is like this (in Pseudocode):
do something
if something failed:
handle the error
try something (line 1) again
else:
we are done!
Here is an example in C++
The code prompts the user to input a number and does so until the input is valid. It uses cin.fail()
to check if the input is invalid. When cin.fail()
is true
I have to call cin.clear()
and cin.ignore()
to be able to continue to get input from the stream.
I am aware that this code does not check of
EOF
. The programs we have written are not expected to do that.
Here is how I wrote the code in one of my assignments in school:
for (;;) {
cout << ": ";
cin >> input;
if (cin.fail()) {
cin.clear();
cin.ignore(512, '\n');
continue;
}
break;
}
My teacher said was that I should not be using break
and continue
like this. He suggested that I should use a regular while
or do ... while
loop instead.
It seems to me that using break
and continue
is the simplest way to represent this kind of loop. I actually thought about it for quite a while but did not really come up with a clearer solution.
I think that he wanted me to do something like this:
do {
cout << ": ";
cin >> input;
bool fail = cin.fail();
if (fail) {
cin.clear();
cin.ignore(512, '\n');
}
} while (fail);
To me this version seems alot more complex since now we also have variable called fail
to keep track of and the check for input failure is done twice instead of just once.
I also figured that I can write the code like this (abusing short circuit evaluation):
do {
cout << ": ";
cin >> input;
if (fail) {
cin.clear();
cin.ignore(512, '\n');
}
} while (cin.fail() && (cin.clear(), cin.ignore(512, '\n', true);
This version works exactly like the other ones. It does not use break
or continue
and the cin.fail()
test is only done once. It does however not seem right to me to abuse the "short circuit evaluation rule" like this. I do not think my teacher would like it either.
This problem does not only apply to just cin.fail()
checking. I have used break
and continue
like this for many other cases that involve repeating a set of code until a condition is met where something also has to be done if the condition is not met (like calling cin.clear()
and cin.ignore(...)
from the cin.fail()
example).
I have kept using break
and continue
throughout the course and now my teacher has now stopped complaining about it.
What are your opinions about this?
Do you think my teacher is right?
Do you know a better way to represent this kind of problem?
while (true)
and instantly assume there's abreak
,return
, orthrow
somewhere in there. Introducing an extra variable that needs to be kept track of just to dodge abreak
orcontinue
is counterproductive. I'd argue the problem with the initial code is that the loop never finishes an iteration normally, and that you need to know there's acontinue
inside theif
to know thebreak
won't be taken.dataIsValid
is mutable, so to know that the loop terminates correctly I need to check that it's set when the data is valid, and also that it's not unset at any point afterwards. In a loop of the formdo { ... if (!expr) { break; } ... } while (true);
I know that ifexpr
evaluates tofalse
, the loop will break without having to look at the rest of the loop body.