is_at_eof: request for critique

G

Gennaro Prota

Please, critique as much as you can about this function:

bool
is_at_eof( std::istream & in )
{
typedef std::istream::traits_type
traits_type ;

assert( ! in.bad() ) ;

return in.rdbuf() != NULL
&& in.rdbuf()->sgetc() == traits_type::eof() ;
}
 
A

Alf P. Steinbach /Usenet

* Gennaro Prota, on 16.10.2010 17:02:
Please, critique as much as you can about this function:

bool
is_at_eof( std::istream& in )
{
typedef std::istream::traits_type
traits_type ;

assert( ! in.bad() ) ;

return in.rdbuf() != NULL
&& in.rdbuf()->sgetc() == traits_type::eof() ;
}

Well, I dunno. As you know (?) I hate them iostreams. But lemme guess.
Presumably sgetc() behaves like a sort of peek thing? And possibly then this
function avoids setting failbit? And then possibly that avoids silly-exception
when exceptions have been enabled?

Befuddled (just out of bed, no coffee yet)

- Alf
 
J

Juha Nieminen

Alf P. Steinbach /Usenet said:
As you know (?) I hate them iostreams.

I'm curious to know why.

C++ streams are type safe and abstract (which makes them usable eg. in
templated code, unlike eg. C streams which cannot be used if the element
to output/input is a template parameter, for obvious reasons), as well
as exception-safe (in other words, if you open a stream in a function,
you don't need to worry about unexpected exits (such as an exception
being thrown) leaking the file handle). They are also expandable: You
can create your own type and add support for input/output streams, so
that they can be handled with the same syntax as anything else (which
is not only convenient, but actually necessary eg. in templated code).

Contrast that with C streams: They are very type-unsafe, you cannot
use them for unknown types (eg. in templated code), they are a leaking
hazard waiting to happen because they are not exception-safe (how many
people bother to surround C stream code with try/catch blocks?) and they
cannot be expanded with user-defined types.
 
S

Steve Pope

Juha Nieminen said:
C++ streams are type safe and abstract (which makes them usable eg. in
templated code, unlike eg. C streams which cannot be used if the element
to output/input is a template parameter, for obvious reasons), as well
as exception-safe (in other words, if you open a stream in a function,
you don't need to worry about unexpected exits (such as an exception
being thrown) leaking the file handle). They are also expandable: You
can create your own type and add support for input/output streams, so
that they can be handled with the same syntax as anything else (which
is not only convenient, but actually necessary eg. in templated code).
Agree

Contrast that with C streams: They are very type-unsafe, you cannot
use them for unknown types (eg. in templated code), they are a leaking
hazard waiting to happen because they are not exception-safe (how many
people bother to surround C stream code with try/catch blocks?) and they
cannot be expanded with user-defined types.

In the above, what is a "C stream" exactly?

I can think of a couple usages, one being that some people call
file pointers "streams", the other being an I/O arthictecture called
"streams" that Bell Labs came up with some number of years ago,
as an alternative to TCP/IP.

Steve
 
A

Alf P. Steinbach /Usenet

* Juha Nieminen, on 16.10.2010 22:39:
I'm curious to know why.

Inefficient, complex, misleading and cryptic names. Books have been written
about using them (not necessary with any decent design). They use that
abomination, two-phase initialization. They don't support exceptions (or rather,
the support that's present is completely impractical and unusable). They're
modal, in particular error mode, but also all that formatting stuff. They
willy-nilly mix abstraction levels. They strongly couple locale and
internationalization stuff to basic i/o. They even have Undefined Behavior for
the most basic things, such as inputting hex numbers. And so on.

C++ streams are type safe

Nope, they're not.

They're just a little less type-unsafe than some available alternatives.

So, they're good for novice/toy/exploration programs.

and abstract (which makes them usable eg. in
templated code, unlike eg. C streams which cannot be used if the element
to output/input is a template parameter, for obvious reasons), as well
as exception-safe (in other words, if you open a stream in a function,
you don't need to worry about unexpected exits (such as an exception
being thrown) leaking the file handle). They are also expandable: You
can create your own type and add support for input/output streams, so
that they can be handled with the same syntax as anything else (which
is not only convenient, but actually necessary eg. in templated code).

Yeah, like a feature list ad for a Microsoft app. :)

Contrast that with C streams: They are very type-unsafe, you cannot
use them for unknown types (eg. in templated code), they are a leaking
hazard waiting to happen because they are not exception-safe (how many
people bother to surround C stream code with try/catch blocks?) and they
cannot be expanded with user-defined types.

Dunno, but it sounds like a straw-man argument.


Cheers & hth.,

- Alf
 
M

Maxim Yegorushkin

Please, critique as much as you can about this function:

bool
is_at_eof( std::istream& in )
{
typedef std::istream::traits_type
traits_type ;

assert( ! in.bad() ) ;

return in.rdbuf() != NULL
&& in.rdbuf()->sgetc() == traits_type::eof() ;
}

What is the use for it? Can you not just read your data till eof?
 
B

Brian Wood

  I'm curious to know why.

  C++ streams are type safe and abstract (which makes them usable eg. in
templated code, unlike eg. C streams which cannot be used if the element
to output/input is a template parameter, for obvious reasons), as well
as exception-safe (in other words, if you open a stream in a function,
you don't need to worry about unexpected exits (such as an exception
being thrown) leaking the file handle). They are also expandable: You
can create your own type and add support for input/output streams, so
that they can be handled with the same syntax as anything else (which
is not only convenient, but actually necessary eg. in templated code).

  Contrast that with C streams: They are very type-unsafe, you cannot
use them for unknown types (eg. in templated code), they are a leaking
hazard waiting to happen because they are not exception-safe (how many
people bother to surround C stream code with try/catch blocks?) and they
cannot be expanded with user-defined types.


[2003 post]
> It seems that cout << ist 3x slower than printf().
> Could somebody please explain why << is so slow?

Here's what I got after testing similar code (10,000 repetitions of
each)
with MS VC++ 7.1 (using Microsoft's library, including iostreams):

stdio: real=0.828136, user=0.015625, kernel=0.015625
iostream: real=2.03128, user=0.09375, kernel=0.171875

stdio: real=0.843761, user=0.03125, kernel=0.015625
iostream: real=2.03128, user=0.0625, kernel=0.171875

stdio: real=0.843761, user=0.03125, kernel=0.140625
iostream: real=2.0469, user=0.125, kernel=0.328125

Then I ran the code under Quantify and it turned out that actual (in
Q's
opinion) time for the execution of the respective functions is almost
4x
different. 100% of the time in stdio version is spent in _output() and
its
descendants. In iostream version, the same _output() (by way of
sprintf())
is used to process the integer output into a character buffer, after
which
the locale-based conversion of the output is applied (which does
exactly
zilch in this particular case). Rough breakdown is this: 25% in
_output(),
almost 50% in this arcane "polishing" code and another 25% lost
somewhere in
iostream housekeeping and call overhead for _NUMEROUS_ functions.

What ever happened to "you don't pay for what you don't use", I
wonder...

.....Max...

[/2003 post]


Iostreams seem to me like a stagnant swamp. I'm more
optimistic about stdio being refurbished with new C++
functionality than the problems of iostreams ever
being successfully addressed.

Brian Wood
Ebenezer Enterprises
http://webEbenezer.net
 
J

Juha Nieminen

Alf P. Steinbach /Usenet said:
Nope, they're not.

They're just a little less type-unsafe than some available alternatives.

"Just a little"? And *I* am the one making straw man arguments?
So, they're good for novice/toy/exploration programs.

Well, if you want to avoid them, by all means. I have used them
successfully and without problems in my programs (including the ones
I make as my payjob). They are considerably easier and safer to use
than the only other alternative. (The Boost formatting class could be
of some use in some situations, but it's used with the regular C++
streams anyways, so the only advantage you get is easier formatting
if you need it.)
Yeah, like a feature list ad for a Microsoft app. :)

I am the one making straw man arguments?

Did you actually have any actual counter-argument to what I said above?
Dunno, but it sounds like a straw-man argument.

There are only two alternatives in the current C++ standard: iostreams
and the C stream functions. How is comparing the former to the latter
"a straw-man argument"?
 
J

Juha Nieminen

Brian Wood said:
[2003 post]
It seems that cout << ist 3x slower than printf().
Could somebody please explain why << is so slow?

Here's what I got after testing similar code (10,000 repetitions of
each)
with MS VC++ 7.1 (using Microsoft's library, including iostreams):

I know that all known implementations of iostream are slower than the
equivalent C stream implementationa (even though in theory the C++ stream
implementations could conceivably be *faster* because there's no need for
format string parsing). However, my attitude towards that is: Know your
tools. If you need extreme I/O speed, use the C stream functions (but be
aware of their problems). If you don't need speed and prefer safety and
versatility, use the C++ streams.

This is no different from chosing your data containers approperiately:
std::vector is good for some things and std::set for others. With one you
get compromises you don't get with the other (eg. std::vector consumes
less memory and keeps all elements in adjacent memory locations, but
pointers and iterators get invalidated if you add new elements, while the
opposite is true for std::set.) You always have to choose appropriately.
 
Ö

Öö Tiib

There are only two alternatives in the current C++ standard: iostreams
and the C stream functions. How is comparing the former to the latter
"a straw-man argument"?

In practice one can (and often has to) use something outside of C++
standard. Once he does it for whatever reasons ... then it is not hard
to notice alternatives. It is more hard to find a framework without
its own "QTextStream" or "wxFile" stuff in it. That makes it somewhat
a straw-man argument.

I am not arguing that every alternative is more useful than iostream
but it is hard to find uglier one.
 
J

Juha Nieminen

Öö Tiib said:
In practice one can (and often has to) use something outside of C++
standard. Once he does it for whatever reasons ... then it is not hard
to notice alternatives. It is more hard to find a framework without
its own "QTextStream" or "wxFile" stuff in it. That makes it somewhat
a straw-man argument.

If you can use a third-party I/O library (which is better than both
standard collections of I/O functions/classes), and there's no technical
or other type of problem in using such a library, and there are clear
advantages in doing so, then it's naturally a good idea to do so.

However, sometimes that's not really an option. Sometimes you have to
develop for a platform with no such library (either the library cannot
be used at all on that platform, or it would be too troublesome to try
to port it). Sometimes you simply are making a portable program/library
and you want to minimize dependencies on third-party libraries in order
to make the usage of your program/library as trouble-free as possible.
(Of course a third alternative is to code your own portable wrapper
around the C I/O functions, but that could often be too much work to
be worth the trouble.)

And sometimes there simply is no need, as the standard C++ (or
sometimes even C) libraries suffice for what you are doing. It definitely
makes no sense to shun the standard library just out of principle.
 
A

Alf P. Steinbach /Usenet

* Juha Nieminen, on 17.10.2010 15:09:
Did you actually have any actual counter-argument to what I said above?

I wasn't aware that we were arguing something.

You asked for a clarification. I gave it. You snipped it.

Your debating technique here is somewhat trollish.


Cheers & hth.,

- Alf
 
M

Miles Bader

Öö Tiib said:
I am not arguing that every alternative is more useful than iostream
but it is hard to find uglier one.

Oh brother...

iostreams certainly has its issues, but it's perfectly fine for typical
usage (std::cout << "program succeeded!" << std::endl;), and not
particularly ugly.

[While the original decision to overload << does seem pretty
questionable, by now that particular usage has become so idiomatic that
it basically isn't an issue anymore.]

-Miles

p.s. The fact that it irritates Alf is a bonus of course...
 
A

Alf P. Steinbach /Usenet

* "Miles Bader", on 18.10.2010 01:13:
Oh brother...

iostreams certainly has its issues, but it's perfectly fine for typical
usage (std::cout<< "program succeeded!"<< std::endl;), and not
particularly ugly.

[While the original decision to overload<< does seem pretty
questionable, by now that particular usage has become so idiomatic that
it basically isn't an issue anymore.]

-Miles

p.s. The fact that it irritates Alf is a bonus of course...

-- Run away! Run away!

Far too many trolls now.

Who the **** are you?


Cheers,

- Alf
 
Ö

Öö Tiib

Oh brother...

iostreams certainly has its issues, but it's perfectly fine for typical
usage (std::cout << "program succeeded!"  << std::endl;), and not
particularly ugly.

Yes indeed. People get accustomed with anything that is useful. Most
programs need logging ... so iostreams provides std::clogging << (TM)
it up. If it is funny or ugly is matter of taste.
[While the original decision to overload << does seem pretty
questionable, by now that particular usage has become so idiomatic that
it basically isn't an issue anymore.]

OK, operator <<() is livable. The operator void*() is bad practice by
most industry coding standards. Its usage with iostreams is also
idiomatic. As soon some novice finds out how it works he does same
within some of his own classes. Explain then how it can be that
std::basic_ios contains indeed a bad practice by most C++ coding
standards.
 
G

Gennaro Prota

What is the use for it? Can you not just read your data till eof?

Well, having this would have a double purpose: first, as you
know, calling eof() on a given istream object isn't a reliable
way to know if it is at eof or not; second, I would put it in
its own translation unit and insulate the very odd set of
#includes that it requires (see the part that starts with "say I
want to write this incredibly simple incantation" in

<http://groups.google.com/group/comp.std.c++/msg/54f4a60825b15267>

)

But here's a possible context and some more specific questions.

I have a little tool (part of Breeze ---see my signature) to
generate include guards. It can do so for a file that is just
being created, of course, but even around existing content. Any
existing content must be piped to the standard in. An early
version of the tool just did something like:

out << "#ifndef " << name << '\n' ;
out << "#define " << name << '\n' ;
out << in.rdbuf() ; // (a)
out << "#endif" << std::endl ;

(where out and in are references to std::cout and std::cin).

Now, the stream inserter from a streambuf *, used at (a), sets
failbit (on the output stream) if no characters are extracted
from input.

In my case, however, this seems just a normal possibility, at
least if the reason why no characters are extracted is simply
end-of-file on std::cin; and I don't want that this causes the
subsequent out << "#endif" to do just nothing, of course.

<note>
This early version worked for me anyway, because even for a
new (empty) file I was actually piping a sequence of newlines,
in order to "space out" the #define from the closing #endif.
But obviously I didn't want to rely on this fact.
</note>

First off, I discarded the following:

out << in.rdbuf() ;
out.clear( std::ios::failbit ) ;
out << "#endif" << std::endl ;

because it clears failbit "blindly"; I suppose the standard
library could turn it on for other (valid) reasons than eof on
input.

So I replaced (a) with a call to the following function:

// A wrapper around
//
// out << in.rdbuf() [1]
//
// with the primary purpose to just skip reading if the input
// stream is already at eof (in that case, [1] sets failbit on
// the output stream, instead).
//
// Secondarily, it turns badbit on in the input stream if it has
// no attached buffer ([1] would set it in the *output* stream).
// ---------------------------------------------------------------------------
std::eek:stream &
transfer( std::eek:stream & out,
std::istream & in )
{
assert( ! out.bad() && ! in.bad() ) ;

typedef std::streambuf
buffer_type ;

buffer_type * const buf( in.rdbuf() ) ;
if ( buf == NULL ) {
in.setstate( in.badbit ) ;
} else if ( buf->sgetc() != EOF ) {
out << buf ;
}
return out ;
}

What do you think about it?

The buf->sgetc() != EOF part is a possible context where the
is_at_eof() of the original post could be used. Here's a more
concise version of it:

bool
is_at_eof( std::istream & in )
{
assert( ! in.bad() ) ;

return in.rdbuf() != NULL
&& in.rdbuf()->sgetc() == EOF ;
}

Please, disregard the fact that it's not really necessary, here.
Indeed I'm not using it yet for the include_guard tool, but it
brings some questions on which I'd like your opinion. I know
that rivers of ink... ehm... gazillions of keystrokes have been
poured on the subject of (predictive) eof over the C++
newsgroups, so I'm cautious.

My main doubts are:

- If in.eof() is true, is it correct that I just ignore it and
go taking sgetc()? (More data might have become available
after eof was set, of course, but the I/O library is complex
enough that I wonder if going on anyway and attempt a sgetc()
doesn't lead to UB.)

- if rdbuf() is null the function returns false: indeed it would
not be correct to say that the stream is "at eof", however it
probably makes more sense to "invert the logic" to

bool has_more_data( std::istream & in )
{
assert( ! in.bad() ) ;

return in.rdbuf() != NULL
&& in.rdbuf()->sgetc() != EOF ;
}

? Should we assert if rdbuf() is null? Should we set badbit
instead?
 
M

Maxim Yegorushkin

What is the use for it? Can you not just read your data till eof?

Well, having this would have a double purpose: first, as you
know, calling eof() on a given istream object isn't a reliable
way to know if it is at eof or not; second, I would put it in
its own translation unit and insulate the very odd set of
#includes that it requires (see the part that starts with "say I
want to write this incredibly simple incantation" in
[]

Please, disregard the fact that it's not really necessary, here.
Indeed I'm not using it yet for the include_guard tool, but it
brings some questions on which I'd like your opinion. I know
that rivers of ink... ehm... gazillions of keystrokes have been
poured on the subject of (predictive) eof over the C++
newsgroups, so I'm cautious.

My main doubts are:

- If in.eof() is true, is it correct that I just ignore it and
go taking sgetc()? (More data might have become available
after eof was set, of course, but the I/O library is complex
enough that I wonder if going on anyway and attempt a sgetc()
doesn't lead to UB.)

- if rdbuf() is null the function returns false: indeed it would
not be correct to say that the stream is "at eof", however it
probably makes more sense to "invert the logic" to

bool has_more_data( std::istream& in )
{
assert( ! in.bad() ) ;

return in.rdbuf() != NULL
&& in.rdbuf()->sgetc() != EOF ;
}

? Should we assert if rdbuf() is null? Should we set badbit
instead?

Having to deal with so many details sounds more complicated that it
should be. Just to detect the end of file should not be hard, should it?

Sorry to disappoint you, but I would not consider C++ as the tool for
generating include guards. You can do that with about three lines of
python code.

If you do insist on using C++, iostreams are notorious for less than
useful error reporting, I can never remember what the difference is
between failbit and badbit.

Stick with POSIX read() call, even Windoze supports that. You will need
to do your own buffering though, but that should take less mental effort
than trying to figure eof using iostreams.
 

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

Forum statistics

Threads
473,756
Messages
2,569,540
Members
45,025
Latest member
KetoRushACVFitness

Latest Threads

Top