Stream states questions

J

john

Erik said:
Nope, it is just you interpretation that is wrong. Note the word *also*,
which says that the failbit can be set without badbit, but tells us
nothing about the reverse.

OK, thanks for the clarification.

In this way, checking an istream in the style "while(cin)" is equivalent
to "while(cin.rdstate() ^ istream::badbit || cin.rdstate() ^
istream::failbit)", that is if both are inactive.

It is more broad than Alf said.
 
J

john

john said:
Correction:



OK, thanks for the clarification.

In this way, checking an istream in the style "while(cin)" is equivalent

==> to "while(cin.rdstate() ^ istream::badbit && cin.rdstate() ^
 
?

=?ISO-8859-1?Q?Erik_Wikstr=F6m?=

==> to "while(cin.rdstate() ^ istream::badbit && cin.rdstate() ^

Actually, as Alf said in his reply to the OP, "while(cin)" is equivalent
to "while(!cin.fail())", or as the standard puts it: "If fail() then a
null pointer; otherwise a non-null pointer to indicate success."
 
J

James Kanze

* john:
I am reading TC++PL3 and in "21.3.3 Stream State", 4 member functions
returning bool are mentioned:
template <class Ch, class Tr= char_traits<Ch> >
class basic_ios: public ios_base {
public:
// ...
bool good() const; // next operation might succeed
bool eof() const; // end of input seen
bool fail() const; // next operation will fail
bool bad() const; // stream is corrupted
[...]
};
It is also mentioned:
"If the state is good() the previous input operation succeeded. If the
state is good(), the next input operation might succeed; otherwise, it
will fail.
==> Applying an input operation to a stream that is not in the good()
state is a null operation as far as the variable being read into is
concerned."
Q1: What does the above mean?
It means that in an ungood state, stream input and output
operations do nothing at all (except possibly throwing
exceptions, if you have turned that on).

It might also change the state.

I'm not sure I actually like the way the statement is formulated
(supposing it was quoted correctly, and there is no missing
context). While it's true that if good() is true, the previous
operation succeeded, it's not necessarily true that if good() is
false, it failed. When good() returns true, it tells you
nothing, and when it returns false, it only tells you that the
next operation will fail; it says nothing about the preceding
operation. (And in the C++ I/O model, it is the results of the
preceding operation which interest us.)
It helps to consider that fail() checks one bit in a set of possible
problem flags: badbit, eofbit and failbit.

Fail() checks both badbit and failbit. Bad() checks only
badbit, eof() only eofbit(), and good() all three.
good() is not a separate bit, and it's not the inverted fail
bit: good() says that /all/ the three problem bits are zero.
Alles in ordnung.

The problem is that even if eofbit is true, it's still alles in
Ordnung. Until the next attempt to read something.
But note that the only way eof() is set automatically, is by
failing to read beyond end of file, which tends to also set
the fail bit.

There's a very important difference. Any time the istream sees
an EOF, it sets eofbit. Including when looking ahead to find
the end of an input element. Thus, if the stream contains just
"123" (no final newline), and you use >> to input into an int,
eofbit will be set (and eof() will return true, and good()
false), even though the input succeeded, fail() returns false,
because the parser for int must read ahead until the first
character which is not part of the int.
Also note that operator void* (used for conversion to logical
boolean) and operator! (ditto) just check the failbit.

No, they check fail(), which checks failbit and badbit.
In other words, let s be a stream object, then if(s){...} is
not the same as if(s.good()){...}, it's the same as
if(!s.fail()){...}. It's all very perplexing. But, remember,
you can just say NO to iostreams.

And what do you use in their place? <stdio.h> is broken to the
point of being unusable. The overal abstraction for iostream
isn't really that bad---it's better than any of the alternatives
I've seen proposed, at any rate. It is regrettable that the
state functions are so poorly named (and in fact, that more
state information isn't always available), but that's a minor
detail.
 
J

James Kanze

Have you found one real advantage of iostreams over the 'C subset'?

They work, they're usable, and they're relatively reliable.
None of which is true for the C subset.
 
J

James Kanze

Sense and sense... There have been long discussions here and in the
moderated group about when exactly eofbit and failbit "should" be set
according to the standard, and when they're actually set with given
implementations.

Do you actually know of implementations which aren't conform
here, or are you just spouting FUD? For the pre-defined types,
this is one of the few things the standard didn't change
compared to the classical iostreams. And I've never seen an
implementation which got it wrong.
That aside, if the streams are set up to generate
exceptions on failure, then you're not guaranteed to avoid exception on
detecting end of file, which makes that feature rather useless.

Have you ever actually tried it? If you're stupid enough to
request an exception on eofbit, you'll get one whenever the
implemention reaches eof. If you ask for one on failbit (not
usually recommended either, but useful in some cases), then
you'll get one on failbit, and only on failbit. And if you ask
for one on badbit (highly recommended), then you'll get one on
badbit, and only on badbit.
I'd think so, but fail() only checks the failbit.

This is completely false.
If failbit were equivalent to eofbit||badbit, then failbit
would be redundant, meaningless.

Failbit is failbit. The function fail() returns (io_status &
(failbit | badbit)) != 0.
So there must be situations where either eofbit doesn't imply
failbit, or badbit doesn't imply failbit. My feelings about
iostreams are such that I have not investigated what those
situations are.

In sum, you're arguing about something you know nothing about.
The convention is to use "!s.fail()", expressed as "s".
The C functions are simple and more efficient but not type safe.

The C functions for formatting are not at all simple; they
require learning an additional, very obtuse language. They are
not type safe, not extendable to user defined types, don't
support logical markup, and can't be used for anything *but*
files and C-style strings. I/O stream is only marginally
simpler than printf when it comes to formatting---the formatting
commands have mnemonic names, but that's about it---, but it
beats the C functions by several orders of magnitude on all
other criteria.
However, the iostreams' formatted input is defined in terms of C fscanf,
and inherits the Undefined Behavior of fscanf. For example, when
inputting hex -- yes, iostreams have built-in Undefined Behavior!

Not just hex. That's something they didn't change from C. But
should have. (In practice, I don't think it's a problem, as
most implementations do the right thing anyway.)
The problem is that in the C and C++ standards there are no
generally good i/o facilities (I think Posix defines the old
Unix open etc. as a generally clean and good but very very
low-level i/o facility).

The problem with the C I/O is that it tries to cover both the
very low (Posix) level, and formatting, in a single abstraction.
For very simple tasks the iostreams are good because they're
relatively safe, thus, well suited to typical beginner's
experimental programs, but bring in e.g. input of hex or
numbers, or text handling like uppercasing, or anything not
very simple, and the complexity, inefficiency, verbosity and
unsafety meet you head on.

It depends on what you're doing. I do agree that where I/O is
concerned, one size does not fit all, and most of my I/O is also
hand written, based on the Posix interface. But using
[io]stringstream for the formatting---I'm not about to rewrite
conversion to/from double.
 
J

James Kanze


[...]
Uppercasing is one of the thorniest problems in data
processing, in general, because natural languages have all
sorts of irrational rules.
But it is of course easy if you restrict yourself to the English
alphabet, /and/ is happy with using only the C library.

I'm not sure how uppercasing entered into the discussion to
being with; it has nothing to do with I/O. In general, you're
right, in that neither C nor C++ have any real support for upper
casing, which takes into consideration that the mapping is not
only locale dependent, but also not necessarily one to one. (In
German single lower case character may map to a string of two
upper case characters, and the mapping for some lower case
characters is different in Switzerland than it is in
Germany---in fact, to map correctly for Switzerland, you need to
distinguish between title case and upper case.) If you don't
need to support such cases, however, the std::ctype facet in
<locale> can be used directly on char; the C functions in
<ctype.h> require conversion to unsigned char first.
 
J

James Kanze

Alf P. Steinbach wrote:
I suppose we do not have undefined behaviour since we have the
istream/ostream::good(),fail(),bad(),eof() etc facilities. So if an
hexadecimal is expected and a decimal is entered, we get
cin.good()==false.

And how is the system to know that 10 was meant to be decimal,
and not hexadecimal?

The problem Alf is referring to is the fact that undefined
behavior occurs if the value read is too large to fit into the
target type.
Yes, however we have wchar_t and its facilities. In most systems
supporting Unicode, wchar_t is Unicode character type so in
<cwctype>/<wctype.h> we have towupper() which does the job.

I suggest you find out a bit more about case handling before
making such blanket statements. It's a non-trivial operation,
and requires considerable thought and effort to be handled
correctly in the general case.
 
J

James Kanze

[...]
As an example, uppercase of German "ß" (small letter sharp s) is "SS"
which, as you may note, consists of /two/ characters, whereas towupper
is a function that at most can produces /one/ character. With at least
one implementation it just produces "ß" as uppercase. And ß" is lowercase.

In every implementation I've seen, it produces "ß". I think
that this is required, in fact. According to the standard,
std::ctype::toupper returns "the corresponding upper-case
character if it is known to exist, or its argument if not."
 
J

James Kanze

A rare day when I get to correct Alf, but fail() returns true if either
failbit or badbid is set. I'm not sure however, if badbit can be set
without failbit being set.

It's rather the opposite: there is no case when both should be
set. Generally speaking, badbit represents a real hardware
error, failbit represents either a formatting error or a lack of
data (end of file before having started reading the element).
 
A

Alf P. Steinbach

* James Kanze:
Have you ever actually tried it? If you're stupid enough to
request an exception on eofbit, you'll get one whenever the
implemention reaches eof. If you ask for one on failbit (not
usually recommended either, but useful in some cases), then
you'll get one on failbit, and only on failbit. And if you ask
for one on badbit (highly recommended), then you'll get one on
badbit, and only on badbit.

Ah, language, James, language! I don't know where you got the idea that
I might be stupid. After all, I'm pretty smart. :)

And of course I've tried it, and you do risk getting an exception on
(first detection of) EOF if you ask for exceptions on failbit. And if
you only ask for exceptions on badbit, you're not guaranteed to get an
exception when an input operation fails to read what you requested[1],
so that's not exceptions on failure. In short, to use your chosen
descriptive word here, it's "stupid", and you're wrong.

Treating detection of EOF as an exceptional failure (and more generally,
coupling detection of EOF to failure to read what's asked for) is very
ungood design. For that matter, sticky EOF state, hidden modes, silent
failure, etc. etc. associated with this particular little aspect of
iostreams, it's so bad that even "badbit" and "failbit" don't adequately
convey how badly it fails.


This is completely false.

Erik Wikström corrected that misimpression earlier, else-thread. Now
you're so upset that you're harking on and on about it, as if it
mattered anything at all, and as if it was an additional point every
time you mention it... You're grasping at a straw here, by going to
personal attack and drawing the grandest conclusions from nothing,

[snip]
In sum, you're arguing about something you know nothing about.


Cheers, & hth.,

- Alf


Notes:
[1] E.g. this program

<code>
#include <iostream>
#include <ostream>

#include <cstddef>
#include <stdexcept>
#include <string>

void cppMain()
{
using namespace std;
cin.exceptions( ios::badbit ); // James' recommendation.

// Are we guaranteed that non-throwing input = successful input?
while( !cin.fail() )
{
int x;
cin >> x;
cout << "* " << x << endl;
}
}

int main()
{
try
{
cppMain();
return EXIT_SUCCESS;
}
catch( std::exception const& x )
{
std::cerr << "!" << x.what() << std::endl;
return EXIT_FAILURE;
}
}
</code>

produces with MSVC 7.1 and input 666 plus next line EOF,

<output>
666
* 666
^Z
* 666
</output>

where the last line exemplifies the statement that referred to this note.
 
J

James Kanze

* James Kanze:
Ah, language, James, language! I don't know where you got the
idea that I might be stupid. After all, I'm pretty smart. :)

I know you are. But even smart people don't know everything.
The smartest, of course, know enough to know what they don't
know. That's why I don't understand your posting.
And of course I've tried it, and you do risk getting an
exception on (first detection of) EOF if you ask for
exceptions on failbit.

With what compiler? I've never encountered this.
And if
you only ask for exceptions on badbit, you're not guaranteed to get an
exception when an input operation fails to read what you requested[1],
so that's not exceptions on failure. In short, to use your chosen
descriptive word here, it's "stupid", and you're wrong.

No I'm not. The exception mask is exactly identical with the
bits: if you ask for an exception on eofbit, you get one on
eofbit (which is totally useless). If you ask for one on
failbit, then you get one on failbit, and only on failbit. (At
least according to the standard---I've obviously not tried every
library in existance. But it works correctly with the g++
implementation of the library, Rogue Wave's, the STL port and
Dinkumware.)
Treating detection of EOF as an exceptional failure (and more
generally, coupling detection of EOF to failure to read what's
asked for) is very ungood design.

I'm not particularly happy about the fact that you cannot easily
distinguish between failure due to end of file, and failure due
to a format error. Regretfully, the old C style I/O isn't
particulary good about this either.
For that matter, sticky EOF state, hidden modes, silent
failure, etc. etc. associated with this particular little
aspect of iostreams, it's so bad that even "badbit" and
"failbit" don't adequately convey how badly it fails.

The sticky error states are a good point (and also inherited
from the C I/O). Under Unix, for various reasons, EOF state
also has to be sticky at some level; I agree that it would have
been perhaps better to say that if filebuf::sgetc() returns EOF
once, it must return EOF always. (This is not totally without
problems, either, but problems which could potentially be solved
by addiing some state manipulation functions to streambuf.)

There is a real, very fundamental, problem with both C and C++
I/O: they are too Unix centric.
[1] E.g. this program
<code>
#include <iostream>
#include <ostream>

#include <cstddef>
#include <stdexcept>
#include <string>
void cppMain()
{
using namespace std;
cin.exceptions( ios::badbit ); // James' recommendation.
// Are we guaranteed that non-throwing input = successful input?
while( !cin.fail() )
{
int x;
cin >> x;
cout << "* " << x << endl;
}

Obviously not. If you have a hard error (a disk read error, for
example), I would expect an exception. But only if you have a
hard error. (And whether the system detects such errors is a
quality of implementation issue---I think most Unix based
systems would just treat them as end of file, in the great Unix
tradition of sticking your head in the sand.)

You don't want an exception for the failure errors. If the
failure is due to no more data, it's a "normal" condition, and
if it is due to a format error in the file, it's also an
"expected" condition, and not exceptional---typically, too, it
will be handled locally by outputting an error message, then
clearing the error status, and skipping ahead to some
resynchronization point where you can resume reading the file.
Usually, the only time you want an exception is when a really
exceptional condition occurs: a hardware read error from the
disk, for example.

Exceptionally, of course, you may feel sure enough about the
format of the file to decide that a format error *is* an
exceptional condition. (If, for example, it is, or should be, a
file written by your program sometime earlier.) You know, for
example, that it contains three integers. In such cases, it
might make sense to request exceptions for failbit as well. And
of course, you will get the exception if the file doesn't
actually contain three integer values.

If your claim is simply that the error states don't provide as
much information as they should, then I totally agree, although
the C++ I/O is slightly better than the C in this regard. (C++
does allow disinguishing between hardware errors and the others,
which is usually fairly important. In most cases, it's also
possible to distinguish between format errors and a real eof,
but it does require more programming than it should, and it
isn't 100% reliable.)
 
J

john

Alf said:
produces with MSVC 7.1 and input 666 plus next line EOF,

<output>
666
* 666
^Z
* 666
</output>


This is very bad. It is good for you to try and avoid such references.
 
A

Alf P. Steinbach

* john:
This is very bad. It is good for you to try and avoid such references.

No, it isn't very bad, it's an illustration of a minor technical point
in a discussion.

Cheers, & hth.,

- Alf
 
J

john

Alf said:
* john:

No, it isn't very bad, it's an illustration of a minor technical point
in a discussion.


It is very bad. It is the number of the antichrist, rather than a
randomly chosen number for illustration purposes.

We should try to avoid making our Father Jesus Christ Who Loves us
without limits, to be sorry about our actions.
 
D

Diego Martins

It is very bad. It is the number of the antichrist, rather than a
randomly chosen number for illustration purposes.

We should try to avoid making our Father Jesus Christ Who Loves us
without limits, to be sorry about our actions.

oh no!
NOT HERE, please!

please, leave and take this f***ing Jesus Christ with you that loves
us without limits and transforms their disciples into boring assholes
 
J

Jerry Coffin

[ ... ]
No I'm not. The exception mask is exactly identical with the
bits: if you ask for an exception on eofbit, you get one on
eofbit (which is totally useless).

While certainly the least often to be useful, I can't agree that even
that one is totally useless. An obvious example would be if the program
has previously written out a temporary file so the contents should be
precisely predictable. If it encounters eof while reading what it knows
should be available, that might well be a truly exceptional condition.

I'd agree for the usual situation of reading a normal input file
supplied by a user though.
If you ask for one on
failbit, then you get one on failbit, and only on failbit. (At
least according to the standard---I've obviously not tried every
library in existance. But it works correctly with the g++
implementation of the library, Rogue Wave's, the STL port and
Dinkumware.)

The fact that some library somewhere might contain a bug doesn't mean
anything about the behavior required by the standard.
Exceptionally, of course, you may feel sure enough about the
format of the file to decide that a format error *is* an
exceptional condition. (If, for example, it is, or should be, a
file written by your program sometime earlier.) You know, for
example, that it contains three integers. In such cases, it
might make sense to request exceptions for failbit as well. And
of course, you will get the exception if the file doesn't
actually contain three integer values.

I hadn't read this before writing what I did above, but it sounds like
we pretty much agree on it being a possiblity under just the right
circumstances -- and even picked essentially identical circumstances at
that...

I think it comes down to this: output is somewhat hard, but input is
drastically harder. While I suspect iostreams could be improved somewhat
in this regard, I hope I'll be forgiven if I have doubts about the
possibility of doing a really _good_ job portably at all.
 
J

James Kanze

[ ... ]
No I'm not. The exception mask is exactly identical with the
bits: if you ask for an exception on eofbit, you get one on
eofbit (which is totally useless).
While certainly the least often to be useful, I can't agree that even
that one is totally useless. An obvious example would be if the program
has previously written out a temporary file so the contents should be
precisely predictable. If it encounters eof while reading what it knows
should be available, that might well be a truly exceptional condition.

That's failbit, not eofbit. An exception will be raised by
eofbit even if the stream hits EOF when reading ahead, to
determine where to stop. Thus, for example, if the file
contains just "1234" (no '\n' at the end), and you input it into
an int, eofbit will be set. (There are historical reasons for
this, and Alf is right that it would be nice to be able to have
separate exceptions for a format error and for an absense of
data because of end of file.)
I hadn't read this before writing what I did above, but it sounds like
we pretty much agree on it being a possiblity under just the right
circumstances -- and even picked essentially identical circumstances at
that...

Except that the exception you want is on failbit, and not
eofbit.
I think it comes down to this: output is somewhat hard, but
input is drastically harder. While I suspect iostreams could
be improved somewhat in this regard, I hope I'll be forgiven
if I have doubts about the possibility of doing a really
_good_ job portably at all.

Error handling is probably the point where iostream is the
weakest. Partially, of course, because there's very little you
can specify portably. But it really would have been possible to
have three real error bits, rather than two, and to have had an
eofbit which was only set when input actually failed because of
EOF, and not because eof was encountered during look-ahead.
(For historical reasons, something with the semantics of the
current eofbit is also needed. Once streambuf::sgetc() has
returned EOF, you cannot reliably call it again.)
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,009
Latest member
GidgetGamb

Latest Threads

Top