I found this code fragment in a book:
int ival;
// read cin and test only for EOF; loop is executed even if there are other IO failures
while (cin >> ival, !cin.eof()) {
if (cin.bad()) // input stream is corrupted; bail out
throw runtime_error("IO stream corrupted");
if (cin.fail()) { // bad input
cerr<< "bad data, try again"; // warn the user
cin.clear(istream::failbit); // reset the stream
istream::iostate cin_state = cin.rdstate();
continue; // get next input
}
// ok to process ival
}
If I click 'f' in the command window, then countless "bad data, try again", and cin_state is 0X02, which is equal to badbit. Failbit has not been clear, why?
The issue is that f is never removed from the input stream, so cin >> ival keeps trying to read it over and over again.
You need to skip past it. See, for example, How does istream::ignore( ) work?
While NPE's point about not removing the offending data from the stream is correct, it's not the only (or most egregious) problem.
You should be using cin.clear(), which is the same as cin.clear(ios_base::goodbit) due to a default argument. As you speculated in your comment, cin.clear(istream::failbit) does not reset cin to the good state. In fact, it sets the stream to the failed state. This may seem counterintuitive, but clear sets the state of the stream to (or "clears it to") the passed parameter. There are some other details in regards to its operation, but they aren't germane to this discussion.
Make sure you call clear before ignore, otherwise the latter will have no effect. Finally, to protect against arbitrarily long invalid entries, pass std::numeric_limits<int>::max() to ignore as the first parameter.
The modified code fragment should be:
int ival;
// read cin and test only for EOF; loop is executed even if there are other IO failures
while (cin >> ival, !cin.eof()) {
if (cin.bad()) // input stream is corrupted; bail out
throw runtime_error("IO stream corrupted");
if (cin.fail()) { // bad input
cerr<< "bad data, try again"; // warn the user
cin.clear(); // or cin.clear(istream::goodbit);
istream::iostate cin_state = cin.rdstate();
cin.ignore(std::numeric_limits<int>::max(), '\n');
continue; // get next input
}
// ok to process ival
}
As to why you found this in C++ Primer, I can't say. I haven't read the book, but I know it's fairly well thought of. I'd suggest checking how old your edition is and looking for an errata list.
Related
I am new to c++ and was making a program in c++11 that sorts a list of integers using the bubble sort algorithm. While I was doing this I noticed something weird. This is my code:
#include <iostream>
void bubbleSort(int x) {
bool done;
int list[x] {0};
std::cout << "List:\n";
for (int i=0;i<x;i++) {
std::cout<<i<<':';
std::cin>>list[i];
}
do {
done = true;
for (int i=0;i<x-1;i++) {
if (list[i]>list[i+1]) {
list[i] = list[i]+list[i+1];
list[i+1] = list[i]-list[i+1];
list[i] = list[i]-list[i+1];
done = false;
}
}
} while (not done);
for (int i:list) {
std::cout<<i<<' ';
}
std::cout<<std::endl;
}
int main() {
int n;
std::cout<<"Length of list: ";
std::cin>>n;
bubbleSort(n);
}
If I input a char instead of an int the program outputs numbers leading up to the length of the list then a string of zeros equal to length of the list.
ex: if I input 5 then type 'k' at the input:
1:2:3:4:0 0 0 0 0
My question is, why is it producing this specific output? I would expect an error if it gets the wrong data type. Sorry if my question is confusing. Thanks in advance.
If you enter k when the input is expecting a number. Then the stream will go into an error state.
The problem is that you did not check the state:
std::cin>>n;
// There could be an error in the line above.
// But you did not check for the error.
Also here:
std::cin>>list[i];
// There could be an error in the line above.
// But you did not check for the error.
Try this:
if (std::cin >> n) {
std::cout << "It worked I got the number: " << n << "\n";
}
else
{
std::cout << "Failed to read a number.\n";
}
How does the above work.
Well the result of the operator>> is a reference to a stream. So it reads a value from the stream into n but returns a reference to the stream. This allows you to things like this:
std::cin >> n >> x >> y;
After each operator>> you get a reference to the stream to apply to the next operator>> so you can chain reads together.
When you use a stream in a boolean context (a test like an if or while) it will convert itself to boolean value depending on its internal state. If the internal state is good std::cin.good() then it will return true otherwise it returns false.
So after it completes the operator>> in then converts itself to bool for the if statement. If it is in a good state you know the read worked. If the read failed it would set an internal fail state and good() returns false.
So what happened in your code.
Well the read failed and the state of the stream was set to failed. When a read fails the preferred behavior is that object being read into remain unchanged (this is what happens for POD (standard) types, user defined types this can be a bit more haphazard).
So the value of n remains unchanged.
When you declared n
int n;
You did not define an initial value so it has an indeterminate value. Which means trying to read that value is UB. UB is bad. it means the code can do anything (which it has done). In practical terms (for most systems) it means the variable has an unknowable value and is whatever was left at that memory location from the last variable that used it.
For your specific case:
So you have typed 5 first then k.
So your first read std::cin >> n; worked.
The next read std::cin>>list[i]; failed.
This set the state of the stream to bad. Any subsequent reads do nothing (until you reset the stream state to good). So you are supposed to detect and fix the stream state.
Each subsequent time around the loop the std::cin >> list[i] will do nothing as the stream is in an error state. Which means it will keep its original value (which for this case is defined as zero 0).
Again the correct action here is to read and check the state of the stream. If it fails take corrective action:
if (std::cin >> list[i]) {
// Worked
}
else {
std::cerr << "Bad input. Try again\n";
// reset the state of the stream
// before trying to read again.
std::cin.clear();
if (std::cin >> list[i]) {
std::cerr << "You got it correct this time\n";
}
else {
std::cerr << "User not bright enough to use the app aborting\n";
throw std::runtime_error("Failed Bad User");
}
}
Additional Note
This behavior of streams is good for reading user input. As it allows a natural flow for detecting and writing code for the user to fix the issue. This design is practically the same for all modern languages that have the same pattern.
But this is not a good flow when you have machine input (ie. there are not expected to be any errors in the input and if there was an error there is no way to correct it).
For reading machine input you can set the stream to throw on an error. This allows you to write nice clean easy to read code that when things go wrong (when they should not) then an exception is throw causing the application to correctly terminate (or the exception could be caught).
std::cin.exceptions(std::ios::badbit); // Fail and Bad
I was looking at this post and few other. What happens if ignore() is called when input buffer is already empty? I observed in below code that if ignore() is called when buffer is already empty, it will not work and waits for some character to be entered first.
int main(void)
{
char myStr[50];
cin.ignore (std::numeric_limits<std::streamsize>::max(),'\n');
cout<<"Enter the String\n";
cin>>myStr;
// After reading remove unwanted characters from the buffer
// so that next read is not affected
cin.ignore (std::numeric_limits<std::streamsize>::max(),'\n');
}
cin.clear() after ignore() creates further problem if the buffer is already empty it looks. I guess clearing the buffer after cin() is safe. But what if I do not know the status of input buffer and I clear even when it is already empty? Do I have to check first if input buffer is empty using cin.fail() or something similar if any?
Secondly, cin itself may not be safe as space is not allowed. So getline() is suggested by some SO posts as given here. But does getline() also requires clearing input buffer or is it safe always? Does the code below work without any trouble (it works now, but now sure if it is safe code).
void getString(string& str)
{
do
{
cout<<"Enter the String: ";
getline(std::cin,str);
} while (str.empty());
}
Other SO references:
Ref 3
Breaking down main:
int main(void)
{
char myStr[50];
cin.ignore (std::numeric_limits<std::streamsize>::max(),'\n');
A bad idea, but you noticed that already. There must be a newline in the stream or you sit and wait for one. If the user's not expecting this behaviour you can expect to wait a long time and have a frustrated user. That's a bad scene.
cout<<"Enter the String\n";
cin>>myStr;
Also a bad idea, but for a different reason. >> doesn't know it should stop at 49 characters to prevent overflowing myStr. Bad things happen at that 50th character.
// After reading remove unwanted characters from the buffer
// so that next read is not affected
cin.ignore (std::numeric_limits<std::streamsize>::max(),'\n');
This one is safe. >> won't consume the newline, or any other whitespace and in order for the stream to hand over the data from the console someone must have hit enter and provided a newline.
}
A general rule of thumb is to not ignore unless you have reason to ignore, and if you have reason, ignore right away. Do not wait until before the next stream operation to ignore, be cause what if this operation is the first? Or the previous operation did not leave anything to ignore?. ignore after the operation that left what you want ignored in the stream. So
std::string getfirstword()
{
std::string firstword;
if (std::cin >> firstword)
{
cin.ignore (std::numeric_limits<std::streamsize>::max(),'\n');
return firstword;
}
return ""; // or perhaps
// throw std::runtime_error("There is no first word.");
// is more appropriate. Your call.
}
is good, but
std::string getfirstword()
{
cin.ignore (std::numeric_limits<std::streamsize>::max(),'\n');
std::string firstword;
if (std::cin >> firstword)
{
return firstword;
}
return "";
}
is an offence in the eyes of all that is holy. Don't do it.
As for getline, it gets a line. All of it up to the end of the file or the end of the line, whichever comes first. It also eats the end of the line for you so you don't have to worry about a stray newline harshing your mellow later.
If you only want part of the line, you will have to break it down. Typical usage for this is something along the lines of
std::string line;
if (std::getline(std::cin,line))
{
std::istringstream istr(line);
std::string firstword;
if (istr >> firstword)
{
// do something with firstword
}
else
{
// there is no firstword. Do something else.
}
}
getline reads everything up to and including the newline. It's no longer in the stream, so I'd consider this safe. You don't have to worry about garbage hanging around on the end of the line. You may have to worry about the next line, though.
In C++ primer I found this code:
if (cin.fail())
{ // bad input
cerr<< "bad data, try again"; // warn the user
cin.clear(istream::failbit); // reset the stream
continue; // get next input
}
I am confused that why the istream::failbit is used to set the error state flag, I mean that since the error has occurred (hence the flow is right now in if block then the failbit must be set, they why use it to set the error flag with that again. Where am I wrong in understanding this?
EDIT:
The book says "We print a warning and clear the failbit state", but IMO clear(istream::failbit) is setting the current state of stream with the value contained in failbit. So why the book is setting the stream's state with that of failbit as it will stop cin from functioning as it will be in error state. ++++ By state of a stream, what bit actually is being talked about, is it eofbit, badbit, goodbit, failbit or a combination of them? How can I know the value of these individual bit as well?
std::basic_ios::clear
void clear( std::ios_base::iostate state = std::ios_base::goodbit );
Sets the stream error state flags by assigning them the value of state. By default, assigns std::ios_base::goodbit which has the effect of clearing all error state flags.
If rdbuf() is a null pointer (i.e. there is no associated stream buffer), then state | badbit is assigned. May throw an exception.
Essentially in this case to set bit means that it sets bit to clear state.
If you call clear without parameters, it sets all bits to clear state, by setting "goodbit", which is exclusive with other states. If you mark only certain bit, only that bit will will be set, clearing other bits ( and good bit as well). Anyway, as said above, if during call of this method input buffer of stream is not valid, then clear() also sets badbit to true, so method good() and operator bool will return false and fail() will still return true.
To wit, why one need to clear those bits but keep a error state is depends on further code, often it is to be able to detect that error happened , but being able to request more data from stream (ask for correct input?)
#include <iostream>
#include <limits>
#include <string>
int main() {
using std::cout;
using std::cin;
int a;
do
{
cout << " Please enter an integer number:";
cin.clear();
cin >> a;
if(cin.fail())
{
cout << "Error occured while parsing input.\n";
cin.clear(std::istream::failbit);
}
// do something
if(cin.fail())
{
std::string str;
//now clear everything, to unlock the input.
cin.clear();
cin >> str;
cout << "Wrong input was: " << str << "\n";
cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
// setting fail bit again, so loop will go on
cin.clear(std::istream::failbit);
}
} while(cin.fail());
cout << "Thank you!";
}
Without calling ::clear(std::istream::failbit) and ::ignore the loop would be working forever, because state of the flags and buffer would force an attempt to parse same buffer content over and over. Actually, a that point you may try to reparse it , e.g. read the string and print it. It would be ok to call just clear() but then we need to create own flag that would allow us to react correctly.
The "state" of stream is a private field of type std::ios_base::iostate, which value is equal to a binary combination of it eofbit, badbit, and failbit constants. goodbit constant is equal to zero and represents no-error state. Two accessors that provide read and write operations to this field:
void setstate( iostate state );
iostate rdstate() const;
Note, setstate(state) got effect of clear(rdstate() | state), which means that if clear can set exact value of iostate, setstate can only set new bits to true, but can't clear bits that already set.
int main()
{
std::ostringstream stream;
if (stream.rdstate() == std::ios_base::goodbit) {
std::cout << "stream state is goodbit\n";
}
stream.setstate(std::ios_base::eofbit);
// check state is exactly eofbit (no failbit and no badbit)
if (stream.rdstate() == std::ios_base::eofbit) {
std::cout << "stream state is eofbit\n";
}
}
for each bit there are accessors: fail(), bad(), eof(), good().
Essentially, fail() returns true if (rdstate()|std::ios_base::failbit) != 0, and so on (See 30.5.5.4 basic_ios flags functions, ISO/IEC 14882:2017, Programming
Languages — C++)
operator bool is defined and returns good()
operator! is defined and returns !good()
The line
if (stream.rdstate() == std::ios_base::goodbit)
can be replaced by
if (stream)
because the latter results in contextual conversion to bool.
Effects, associated with iostate's bits (according to ISO C++):
badbit indicates a loss of integrity in an input or output sequence (such as an irrecoverable read error from a file);
eofbit indicates that an input operation reached the end of an input sequence;
failbit indicates that an input operation failed to read the expected characters, or that an output operation failed to generate
the desired characters.
I want to prompt the user to input an integer, but if the user enters a non-integer, the program should keep demanding an integer until the user complies.
int getInteger(){
int input;
do{
std::cout << "Enter an integer: ";
std::cin >> input;
} while(!(std::cin));
return input;
}
If the user enters an integer, the function returns it.
But if the user enters something like "Hello," the function goes on an infinite, cout-ing "Enter an integer: ".
How do I fix this?
!(std::cin)
will evaluate to true if std::cin is in a bad state, e.g. after an input operation failed. Then, all subsequent input operations will fail immediately and not change cin's error state, thus the infinite loop.
To get the behavior you want, you may use something like
while (!(std::cin >> input)) {
std::cout << "Try again\n";
// Clear away the error state
std::cin.clear();
// Ignore what ever garbage is still in the stream
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}
In the real world, you may want to handle the (generally not recoverable) failures eof (someone sent an End of File character) and bad (cin is broken, should not happen) different than fail which happens after invalid input. This is, for example, shown on this reference page for ignore. However, this should not bite you in toy programs like yours seems to be.
Streams convert to true while there is none of the failure bits is set. Once a stream entered the failure state, i.e., std::ios_base::failbit (or std::ios_base::badbit) is set for the stream, it stays in that state until the failure bit is cleared using clear(). In addition to clearing the stated you'd also need to get rid of the offending character(s) causing it to get into this state, e.g., using ignore().
I have a function (addShape) to read ints from a file according to the id it gets. It gets the id and the stream is as parameters. for some reason I get thrown with std::ios_base::failure after reading the last line.
while (is >> id)
addShape(id, is, false);
I thought that this is the safest way to read from a file.
This is how I initialize the stream:
fstream is;
int id = 0;
string filename;
char answer = NULL;
// set exceptions
is.exceptions(fstream::failbit | fstream::badbit);
try { is.open(filename); }
catch (ifstream::failure e)
{
clrscr();
cout << "There was an error opening " << filename << endl;
waitForEscape();
is.close();
return;
}
When you're creating the stream, notice that you're turning on exceptions whenever failbit is set:
// set exceptions
is.exceptions(fstream::failbit | fstream::badbit);
This means that any time a stream operation sets failbit, the stream will throw an exception.
Now, look at this code:
while (is >> id)
addShape(id, is, false);
At some point the read is >> id will fail, either because you run out of data or because the data is malformed. When this happens with exceptions turned off, this will fail by setting failbit and having is >> id evaluate to false, stopping the loop. However, with exceptions turned on, when failbit is set in this case, it will throw an exception.
Depending on what you want to do, you can either
Not set exceptions for failbit, which will cause the loop to stop running when an error occurs, or
Set up an explicit exception handler around the while loop.
Hope this helps!