std::cin and stdin

67 views
Skip to first unread message

lucafranc...@gmail.com

unread,
Apr 18, 2018, 9:11:35 AM4/18/18
to ISO C++ Standard - Discussion
What kind of "synchronization" should I expect between std::cin and stdin? To which extent they can be used interchangeably? For instance, should the set flags associated with them (like the end-of-file) be the same?

What does the standard say about using these two objects in the same program? The only thing I could find is [narrow.stream.objects]/1, but is is not clear to me what does the wording exactly mean.

Michael Witten

unread,
Apr 20, 2018, 12:35:56 PM4/20/18
to lucafranc...@gmail.com, std-dis...@isocpp.org
On Wed, 18 Apr 2018 06:11:35 -0700 (PDT), Luca wrote:

> What kind of "synchronization" should I expect between std::cin and
> stdin? To which extent they can be used interchangeably? For
> instance, should the set flags associated with them (like the
> end-of-file) be the same?
>
> What does the standard say about using these two objects in the same
> program? The only thing I could find is [narrow.stream.objects]/1
> <https://timsong-cpp.github.io/cppwp/iostream.objects#narrow.stream.objects-1>,
> but is is not clear to me what does the wording exactly mean.

For reference, here is that wording:

The object cin controls input from a stream buffer associated with
the object stdin, declared in <cstdio>.

From my perusal of the Standard, that sentence is indeed all that is
said on the matter. Here are my thoughts:

> What kind of "synchronization" should I expect between std::cin and
> stdin?

I think you can expect that `std::cin' (or, rather, its underlying
stream buffer) keeps itself coherent with `stdin'; however, `stdin'
probably doesn't know anything about `std::cin' (or its underlying
machinery) and thus does not keep itself coherent with `std::cin' (or
its underlying machinery).

> To which extent [can they] be used interchangeably?

Given that the Standard says nothing else, you must assume that it
would be incredibly unwise to use both `std::cin' and `stdin' manually
at the same time.

If you use both at the same time, then you are treating `stdin' as a
shared resource; it is being shared between the code that uses
`std::cin' and the code that uses `stdin' directly. Your only hope of
producing a working, portable program is to use that shared resource
very carefully, and the Standard implies that the only way to use that
shared resource very carefully is to ensure that `std::cin' is the
sole user of `stdin'.

That is, in general, you cannot use them interchangeably.

That being said, the rule about synchronization comes into play: If,
for a time, you use only `std::cin', then at the end of that time,
both `std::cin' and `stdin' will be properly "synchronized" with each
other. I suppose that you may thereafter start using `stdin' directly;
however, you must assume that doing so puts `std::cin' and `stdin' out
of synchronization---it's a one-way street, and you may never safely
go back to using `std::cin'. Even then, when your program ends, it
will call the destructor of `std::cin', which means that your program
could try to go back down that one-way street and end up being very
confused; your program could crash on exit, or something silly like
that.

> For instance, should the set [of] flags associated with them[...] be
> the same?

That would be an implementation detail. Maybe `std::cin' sets up
`stdin' to be used in raw "binary" mode, and then performs its own
post-processing on the characters that are read; or, maybe `std::cin'
passes on shared flags to `stdin' and thereby allows `stdin' to handle
most of the processing.

You'd have to check at run-time that `stdin' is in a certain desirable
state, or you'd have to write code that is specific to a particular
implementation.

In short, use one or the other, but not both, unless you are writing
code that is specific to a particular implementation that you
understand really well.

Sincerely,
Michael Witten

lucafranc...@gmail.com

unread,
Apr 21, 2018, 8:38:26 AM4/21/18
to ISO C++ Standard - Discussion, lucafranc...@gmail.com
Thanks Michael for taking time to thoroughly answer a broad question. I agree with your line of thought and your interpretation of the standard wording.

Implementations of the standard library, however, do not seem to agree with this. Consider this program: https://ideone.com/Rx9P01
When given no input (meaning, the first read will already reach the end-of-file), cin uses stdin, which set its end-of-file flag and returns EOF, and so cin set its own end-of-file flag as well: this makes sense.
However, cin.clear() does not seem to reset underlying stdin end-of-file flag. This makes much less sense to me, because cin should keep itself coherent with stdin, and it also brings some consequences:
  • cin and stdin can get out of sync even when using cin alone (of course I had to use the C function feof to test the flag, but we can safely assume it does not change the state of the objects);
  • the end-of-file flag of cin is basically useless in the context of reusing a stream after end-of-file signal, as well as the functions manipulating it, since it does not reflect the state of the underlying C object on which the I/O will actually happen;
  • it is impossible to reuse standard input after end-of-file without using C functions (clearerr(stdin)).
I did not check whether this also happens with error flags as well, nor whether it also happens with wcin.

Now, one could argue that giving the end-of-file signal from the keyboard and then keep using the standard input is poor practice. I agree, but still:
  • I cannot find anything in the standard forbidding this;
  • it works in C;
  • glibc has very recently fixed a long-standing bug in their development version about using stdin after end-of-file signal, meaning they also think stdin should behave correctly after end-of-file, fwiw: https://sourceware.org/bugzilla/show_bug.cgi?id=1190
I fail to find a good reason for an implementation to behave this way. Am I missing something?

Cheers,
Luca Franceschini
Reply all
Reply to author
Forward
0 new messages