C++ Loop Structure – How to Repeat Until Success and Handle Failures

ccoding-styleimperative-programmingioloops

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?

Best Answer

I would write the if-statement slightly different, so it is taken when the input is successful.

for (;;) {
    cout << ": ";
    if (cin >> input)
        break;
    cin.clear();
    cin.ignore(512, '\n');
}

It's shorter as well.

Which suggests a shorter way that might be liked by your teacher:

cout << ": ";
while (!(cin >> input)) {
    cin.clear();
    cin.ignore(512, '\n');
    cout << ": ";
}
Related Topic