seekg, not exactly like the reference said.

hi, i was trying to write a function to copy files, and i stumbled upon this problem.
please read the full post before trying to answer, do not skip any line as i tried many solutions myself before posting

i want to copy a file(1.txt) to a temporary location.
1.txt in text:
123

simple enough.

the problem is: a function processed the file and reached its eof, it sat eofbit to true, then a seekg operation also sat the failbit to true.
the function then called my version of Copy():
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
void  Copy  (istream& in, ostream& out)
{
	ios::iostate debug_ob = 0;
	debug_ob = in.rdstate();

	in.clear();

	in.seekg	( 0 , in.beg );
	out.seekp	( 0 , out.beg );

	debug_ob = in.rdstate();

	char ch;
	while(true)
	{
		ch = in.get();

		if (in.eof())
			break;

		out<<ch;
	}
	
}


this code works fine, but if you replace line 6 in.clear(); with these lines:
1
2
if(in.eof())
    in.clear ( (~ios::eofbit) & in.rdstate() ); //this will unset only the eofbit 

the seekg operation fails.
the reference said :
If the eofbit flag is set before the call, the function fails (sets failbit and returns).
http://www.cplusplus.com/reference/istream/istream/seekg/?kw=seekg

it didn't mention that if failbit is set, the operation also fails.

the reference may be inaccurate in this, on the other hand maybe it's microsoft's implementation of the function that causes this behaviour.
another possibility is that i lack some essential understanding in this domain.

can someone help me understand what's happening please.

one more question: is using clear() safe in programming??
I believe that if the stream has any error flag set, any operation on the stream will fail. With the current standard (C++11) it appears that if only eof() is set the seek will reset the eof flag and preform the seek.

one more question: is using clear() safe in programming??

Yes using clear() without any arguments is safe. This clears all error flags.

Note that streams can be copied by simply out << in.rdbuf();

And yes, C++11 changed the behavior of seekg, it is now possible to seek away from the end of file (on implementations that got around to this requirement). It is documented, for example, at http://en.cppreference.com/w/cpp/io/basic_istream/seekg

A call to clear() is a safe and portable workaround.


PS:
it didn't mention that if failbit is set, the operation also fails.

This site's reference said "Then (if good), it calls either pubseekpos (1) or pubseekoff (2)". When failbit is set, good() is false, so seekg doesn't call anything. I agree that singling out set fail if eof is confusing, since it's part of what sentry constructor does.
Last edited on
Cubbi wrote:
Note that streams can be copied by simply out << in.rdbuf();


thanks man, this is a great advice, i'll make sure to use it in the future.

jlb wrote:
With the current standard (C++11) it appears that if only eof() is set the seek will reset the eof flag and preform the seek.

i think i'm somewhat outdated, i'm writing my project in the 98 standard.

anyway, after i read your comments i started a research and found something:
i mis-spotted the true error in my project, i can now see the true error:

actually my program processed a file (1.txt mentioned above) and saved the process result in a temporary file then called Copy() to move the contents from Temp to 1.txt, the put-pointer in Temp is not in the beginning of the file, maybe this made the get operations to malfunction, that's unlikely the problem however.
another cause is, the processing of 1.txt sat the eofbit, so the seek operation out.seekp(0,ios::beg); failed to continue, that's the true cause in my opinion.
i added out.clear(); to the Copy() function and that solved the problem.

my deep thanks to all of you, your contributions were a great help.
Topic archived. No new replies allowed.