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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With