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!
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
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 know, there was hundreds questions about fail and eof, but no one was able to answered my question.
In this example, only eof bit will be set:
while (!Ifstream.eof()){
Ifstream >> Buffer;
cout << Buffer << endl;
}
But in this example, eof bit as well as fail bit will be set:
while (!Ifstream.fail()){
Ifstream >> Buffer;
cout << Buffer << endl;
}
What is the reason of this two differences? .I consider only situation, when stream reach end of file.
The difference is very slight.
The first piece of code, tries reading as long as it doesn't hit EOF condition. Then it breaks. But, if for some reason an error occurrs (i.e. failure to convert data through << operator), this piece of code will loop indefinitely, since FAIL will be set on error, reading will stop, and EOF will never be hit.
The second piece of code works with a small trick. It reads as long as it can and stops when error occurs. Ok, logical. However, when hittin an end-of-file, but IIRC the EOF condition will not be set yet. So, the loop will run once more, try to read at EOF state, and that will rise the FAIL flag and break the loop. But that also means that you will get one processing ( cout<
The right way to do is to check immediatelly whether READING succeeded:
while (true){
if(!(Ifstream >> Buffer))
break;
cout << Buffer << endl;
}
only that will guarantee you that the loop will stop as soon as read fails, be it EOF or FAIL or other cause.
As MatsPetersson and πάντα ῥεῖ have suggested, the above snippet may be "squashed" to form:
while (Ifstream >> Buffer)
cout << Buffer << endl;
and that's the usual way to write it. No fail/good/eof checks needed. The value returned from operator>> is the stream itself (like in operator<<) and stream is testable for "truthness", so it's just as simple as that. When talking about fail/good/eof differences, I like to write the longer form to emphasize that .. you shouldn't use fail/good/eof in the while-condition at all, and that you should check the state of the stream only after actually trying to read from it. while(true) shows the point very clearly.
fail is different from eof in that it covers various other error conditions than "file reached its end".
For example, if Buffer is int Buffer then the second will stop on reading ABC, where the first one will loop forever (not making any progress, as ABC is not numeric input).
Of course, the CORRECT thing to do is:
while(Ifstream >> Buffer)
{
cout << Buffer << endl;
}
that will stop both on EOF and invalid input (if applicable), as well as not performing the cout << Buffer << endl; when the fail or eof condition happens.
[Note that the while(!eof()) solution is valid in for example Pascal, because in Pascal, the input is "pre-read", so that the current read knows if "the next read will result in EOF" before you actually TRY to read it. C and C++ doesn't mark EOF until you actually READ past the end of the file.
Programically,
'EOF in read' and 'fail of read' is described differently.
EOF indicates End Of File.
So, programmer knows when they have to stop reading file.
But 'fail' is indicates 'not successfully'
It means some process ends with wrong state or exception has been occurred when execute the process.
I'm currently using a technique similar to file >> vec[i] to fill up an array with values from the lines of a file. However, how can I be sure that this will return an error message if the line it tries to read is not a number? It should be allowed to take ints and doubles, but not something like "lol" or 3,24,5.
The general pattern is to check the result of the input operation:
double d;
if (file >> d) { vec[i] = d; }
else { /* error (now you must handle this before trying again) */ }
If an error does occur, you have to decide on some policy for what to do next -- skip over it somehow, terminate the program, etc.
Normally you can just check the fail bit after your read:
cin>>d;
if(cin.fail())
// we failed! Print an error!
or like this:
if (not (cin>>d))
// we failed! Print an error!
But that can be bothersome if you have a lot of reads, as you'll handle errors after each read.
Alternatively, you can turn on the option in cin that throws an exception on failure:
cin.exception(std::ios::failbit);
//...
cin>>d; // will throw on failure
How can I be sure that this will return an error message if the line it tries to read is not a number?
A common technique is to set the stream bits to the exception mask after the input has been performed. Then you can perform cleanup (or rethrow the exception) as you like:
file.exceptions(std::ios_base::goodbit);
while (file >> x)
{
// ...
}
try { file.exceptions(std::ios_base::badbit |
std::ios_base::failbit | std::ios_base::eofbit); }
catch(std::ios_base::failure&)
{
if (file.rdstate() & std::ios_base::failbit)
// ...
if (file.rdstate() & std::ios_base::badbit)
// ...
if (file.rdstate() & std::ios_base::eofbit)
// ...
}
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.