What does istream::sync()?

J

john

I am reading TC++PL3 and on page 644 it is mentioned:

"Flushing an istream is done using sync(). This cannot always be done
right. For some kinds of streams, we would have to reread characters
from the real source - and that is not always possible or desirable.
Consequently, sync() returns 0 if it succeeded. If it failed, it sets
ios_base::badbit (21.3.3) and returns -1. Again, setting badbit might
trigger an exception (21.3.6). A sync() on a buffer attached to an
ostream flushes the buffer to output".


So, what exactly should we expect from an call of sync() on an istream?
Making its streambuf to lose all its contents?

The code:

#include <iostream>


int main()
{
using namespace std;

char c;

cin>> c;

cout<< c<< endl;

int sync_failure= cin.sync();

cout<< sync_failure<< endl;

cin >> c;

cout<< c<< endl;
}


in my system produces:

[john@localhost src]$ ./foobar-cpp
test
t
0
e

[john@localhost src]$
 
G

Gianni Mariani

john wrote:
....
So, what exactly should we expect from an call of sync() on an istream?
Making its streambuf to lose all its contents?
....

istream is allowed to buffer input. If it does so, it will not be able
to see changes to the parts of the file in it's input buffer after the
buffer is filled. What sync appears to do is to expire the content of
the buffer if the input is appropriate (i.e. file based input).

Below is an strace of your code with the source as input. Notice that
it reads the file into memory and after the sync it reads it again but
offset by 1. If after the first read the file had changed, then the
second read would expose the new contents of the file.

read(0, "#include <iostream>\n\n\nint main()"..., 4096) = 241
fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 4), ...}) = 0
write(1, "#\n", 2#) = 2
lseek(0, -240, SEEK_CUR) = 1
write(1, "0\n", 20) = 2
read(0, "include <iostream>\n\n\nint main()\n"..., 4096) = 240
write(1, "i\n", 2i) = 2
exit_group(0) = ?
 
J

James Kanze

I am reading TC++PL3 and on page 644 it is mentioned:
"Flushing an istream is done using sync(). This cannot always be done
right. For some kinds of streams, we would have to reread characters
from the real source - and that is not always possible or desirable.
Consequently, sync() returns 0 if it succeeded. If it failed, it sets
ios_base::badbit (21.3.3) and returns -1. Again, setting badbit might
trigger an exception (21.3.6). A sync() on a buffer attached to an
ostream flushes the buffer to output".
So, what exactly should we expect from an call of sync() on an istream?

Nothing. The standard leaves it entirely up to the
implementation; different implementations do different things.
Making its streambuf to lose all its contents?

Well, it certainly depends on the type of the streambuf; for a
stringbuf, for example, sync is always a no-op. For a file buf,
sync() on input isn't specified by the standard.

Some implementations, I think, simply throw out any data they
happen to have in the buffer. *IF* the implementation is line
buffering the file (as do Unix, and I think Windows, when the
data source is a keyboard), this has more or less the same
effect as ignoring input up to and including the next newline.
Don't use it for this, however, since it will fail if the input
is not line buffered (not from the keyboard). And of course,
it's not standard; other implementations (e.g. g++) simply treat
the sync as a no-op.
 
J

James Kanze

john wrote:
...> So, what exactly should we expect from an call of sync() on an istream?

istream is allowed to buffer input. If it does so, it will not be able
to see changes to the parts of the file in it's input buffer after the
buffer is filled. What sync appears to do is to expire the content of
the buffer if the input is appropriate (i.e. file based input).

That would be logical, wouldn't it. The standard simply says:
"If a get area exists, the effect is implementation defined."
So basically, you can't count on anything. (Practically, of
course, what is "appropriate" for a filebuf, which may be
connected to a tty, a file or even maybe a pipe.)
 
J

john

James said:
other implementations (e.g. g++) simply treat
the sync as a no-op.


I am not sure what you mean by this. I am using g++ under Linux and it
doesn't complain for "cin.sync()".
 
M

Michael DOUBEZ

john a écrit :
I am not sure what you mean by this. I am using g++ under Linux and it
doesn't complain for "cin.sync()".

No-op simply means it doesn't do anything (empty function or removed by
the compiler).

Michael
 
G

Gianni Mariani

john said:
I am not sure what you mean by this. I am using g++ under Linux and it
doesn't complain for "cin.sync()".

I'm not sure either since the strace I showed earlier is from a Linux
system. However don't expect your compiler to complain if somthing is
implemented as a no-op.
 
J

James Kanze

I'm not sure either since the strace I showed earlier is from a Linux
system. However don't expect your compiler to complain if somthing is
implemented as a no-op.

The g++ behavior seems to depend on the system; I get different
behavior under Solaris and Linux. IMHO, it would also be
reasonable for the behavior to be what you describe if the input
is from a regular file, but to be a no-op is isatty is true, or
if the input is from a pipe (named---since I don't think the
current implementation of g++ has any means of getting an
istream from a pipe).

At any rate, the behavior is definitely variable; if I do
something like:

std::cin >> aChar ;
std::cin.rdbuf()->pubsync() ;
std::cin >> aString ;

then input "abcd<RETURN>123", followed by a return and the
system end of file character (^D under Unix, ^Z under Windows),
I'll get "bcd" in aString on some implementations (Sun
CC/Solaris, g++/Linux), "123" on others
(g++/Solaris,VC++/Windows). IIRC, "123" corresponds to the
traditional implementation; what the classical iostream from USL
did. (And of course, a lot of Windows programmers think that
that's what it always does, because that's what VC++ does.)

For a tty, of course. If I put the same data in a file, and
redirect input from that, I get something different with
g++/Solaris and VC++/Windows: "bcd" with g++/Solaris and an
empty string with VC++. The only way I can explain the g++
behavior in this case is that the implementation detects if the
input is a regular file (or not a tty, or something), and
behaves differently. (A very reasonable choice, thinking about
it. Seek back the number of characters in your buffer and throw
out the contents of the buffer if seeking will work; no-op if it
won't. But why don't I get this under Linux, then? My Solaris
and my Linux version were generated from the exact same source
tree.) VC++'s behavior, of course, is exactly what you get by
just throwing out any contents---keyboard input is line buffered
by the system, so you throw out through the end of the line,
file input isn't, so you throw out (in this case) a lot more.

Anyway, I think we agree that there's nothing here you can count
on in portable code.
 

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,965
Messages
2,570,148
Members
46,710
Latest member
FredricRen

Latest Threads

Top