You have a common bug that will send you into an infinite loop. :-)
When reading data (especially user input data) you must validate the read worked correctly. If the read fails and sets one of the error flags on the stream than any subsequent attempt to read will silently be ignored.
Thus usually read operations are checked in the loop test.
std::string word;
while(word != "STOP") {
std::cin >> word;
std::cout << "Word: " << word << "\n";
}
In the above you will enter an infinite loop if your hit an EOF marker (Note: this can be generated from the keyboard) or in unix systems a file can be piped to the input stream of an application etc..
To prevent this you test the result of the read operation.
std::string word;
while(std::cin >> word && word != "STOP") {
std::cout << "Word: " << word << "\n";
}
This works because of two things. The operator>>
returns a reference to the stream (usually for chaining). When a stream is used in a boolean context (like a test) it is converted to a bool using operator bool
which calls good()
which returns true
if the stream is still in a good state (ie the read operation did not cause an error).
Secondly declares variables as close to the use point as possible.
This is a good habit to get into with C++ as objects have constructors that can potentially be expensive (also destructors). Declaring them at the top of the function and then not using them is wasteful.
Also be declaring them near the use point also allows for locality of reading when checking variables types.
In your case:
std::string answer;
This is declared at the top but only used inside the loop.
Also prefer not to use return 0;
in main() when the application never returns an error state. The compiler will automatically generate the required return 0
and leaving it off is a marker used by programs to indicate that the program never fails.
Give this I would rewrite as:
bool checkAnswerOK(std::string& answer, bool& result)
{
std::transform(answer.begin(), answer.end(), answer.begin(),
[](unsigned char x){return ::tolower(x);});
bool answer_valid =
(answer == "y") ||
(answer == "n") ||
(answer == "yes") ||
(answer == "no");
result = answer_valid && answer[0] == 'y';
return answer_valid;
}
bool question_yesno(std::string const& message)
{
std::string answer;
bool result;
std::cout << message << "? [Y/n]\n";
while(std::cin >> answer && !checkAnswerOK(answer, result))
{
std::cout << "Invalid answer: " << answer << " Please try again\n"
<< message << "? [Y/n]\n";
}
if (!std::cin) {
// We never got an answer.
// Not much we can do here. Probably give up?
throw std::runtime_error("User Input read failed");
}
return result;
}
int main()
{
question_yesno("Should the password include digits");
}