Clarification regarding use of flagbit to set internal error flag - c++

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.

Related

Why is failbit set when I enter EOF?

I'm currently learning how while (cin >> num) work and I found out that there are two steps.
First one is the operator>> function return a istream object with error state, and the second is bool converter that convert istream object into bool depend on its state.
But I find it confusing that in the bool convert function, it will return 0 only if failbit or badbit is set. And the operator>> function will set eofbit if it read EOF.
bool convert function: https://www.cplusplus.com/reference/ios/ios/operator_bool/
operator>> function: https://www.cplusplus.com/reference/istream/istream/operator%3E%3E/
In this case, After I enter EOF the bool converter should return 1 because the failbit and badbit aren't set.
Therefore, I use the below program to check what actually happened to the error bit after I enter EOF. And I find out that the failbit will be set after entering EOF!!
So I'm wondering if anyone can help me understand why is failbit set?
#include <iostream>
using namespace std;
int main()
{
int num;
cin >> num;
cout << cin.eof() << " " << cin.fail() << " " << cin.bad() << endl;
return 0;
}
Input: ^Z(on windows using qt creator, non qt c++ project)
Output: 1 1 0
Input: ^D(on windows using qt creator, non qt c++ project)
Output: 0 1 0
eofbit is set when a read operation encounters EOF while reading data into the stream's buffer. The data hasn't been processed yet.
failbit is set when the requested data fails to be extracted from the buffer, such as when reading an integer with operator>>. While waiting for digits to arrive, EOF could occur. eofbit alone is not enough to enter an error state, as there may be usable data in the buffer.
So, for example, imagine a while (cin >> num) loop is used and the user enters 123<Ctrl-Z>.
on the 1st iteration, operator>> reads 1, 2, 3 into the buffer, then encounters Ctrl-Z, so it sets eofbit and stops reading. 123 is then extracted from the buffer into num and the operator exits. At this point, the stream is not yet in an error state. When the stream's bool conversion is evaluated by while, it returns true, allowing the while body to be entered so it can process num.
on the next iteration, operator>> sees eofbit is set, preventing further reading. There is nothing left in the buffer to extract into num, so the operator sets failbit and exits. The stream is now in an error state. When the stream's bool conversion is evaluated by while, it returns false, breaking the while loop.
If the EOF is the first input, the operator>> fails to read an integer, so the stream enters the fail() state.
If you type at least one digit before the Ctrl-Z, that digit is read and the input succeeds.

Why is cin.failbit always set even when input is valid?

I was trying to write a program that asks to input a char array using cin.getline() and if given input is bigger than array length array gets extended.
I used cin.failbit to see if user's input was too long. But nothing went right. So after debugging I figured out that the problem lies in failbit.
So I wrote a simple program to see what was wrong about it and it turned out that somehow cin.failbit always returns true when in if-statement even when input seems valid.
int main () {
char name[256];
std::cout << "Enter your name: ";
std::cin.getline (name,256, '\n');
std::cout << "characters read: " << std::cin.gcount() << std::endl;
if (std::cin.failbit){
std::cin.clear();
std::cout << "failed\n";
}
}
For example, when input is "qwer" program outputs that 5 characters have been read (cin.gcount), so it should be fine but it also outputs "fail" meaning that failbit flag is set. But I believe it shouldn't be in this case.
program output here
So can anyone explain why failbit appears to be set permanently?
Any help will be highly appreciated
std::cin.failbit is a constant that indicates which of the error bits represents stream failure. It is not an indication of the stream's current state. To check if that bit is set, use the member function std::cin.fail() instead.
However, if the stream failed to read due to reaching the end of the stream fail() will return false leading you to believe that it succeeded. Prefer std::cin.good() to check if the last operation succeeded.

What happens when c++ expects one data type and gets another?

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

Why is this file reading code generating exceptions?

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!

Bad data, try again

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.