firefexx
firefexx

Reputation: 786

C++ fstream: throwing exception when reaching eof

I want to read from two files until I reach the end of one of them. If something goes wrong, the fstream should throw an exception.

The problem is, that bad or fail bit is also set when eof bit is set.

ifstream input1;
input1.exceptions(ios_base::failbit | ios_base::badbit);
input1.open("input1", ios_base::binary | ios_base::in);

ifstream input2;
input2.exceptions(ios_base::failbit | ios_base::badbit);
input2.open("input2", ios_base::binary | ios_base::in);

ofstream output;
output.exceptions(ios_base::failbit | ios_base:: badbit);
output.open("output", ios_base::binary | ios_base::out | ios_base::trunc);

char in1, in2, out;

while(!input1.eof() && !input2.eof()) {
    input1.read((char*) &in1, 1);
    input2.read((char*) &in2, 1);
    out = in1^in2;
    output.write((const char*) &out, 1);
}

input1.close();
input2.close();
output.close();

This leads to

$ ./test
terminate called after throwing an instance of 'std::ios_base::failure'
  what():  basic_ios::clear

How to do it right?

Upvotes: 4

Views: 6809

Answers (3)

arayq2
arayq2

Reputation: 2554

The basic problem in your code is a FAQ. You should never use eof() as a test condition of a read loop because in C/C++ (unlike some other languages) eof() is not set to true until you have read past the end of file, and therefore the body of the loop will be entered once too many times.

The idiomatically correct procedure is to have the read operation itself in the loop condition, so that the exit occurs at the correct point:

  while ( input1.get(in1) && input2.get(in2) ) { /* etc */ }
  // here, after the loop, you can test eof(), fail(), etc 
  // if you're really interested in why the loop ended.

This loop will end naturally with the exhaustion of the smaller input file, which is exactly what you want.

Upvotes: 6

Ivaylo Strandjev
Ivaylo Strandjev

Reputation: 70939

Simply remove the .eof() if(fstream) checks all bits (eof bad and fail).

So re write the while as:

 while(input1 && input2)

And then maybe verify that eof() returns true for at last one of the streams.

Hope this helps.

Upvotes: 0

Olaf Dietsche
Olaf Dietsche

Reputation: 74058

Don't throw an exception at all and use input1.read or istream::get in your while condition

while (input1.get(in1) && input2.get(in2)) {
...
}

If you read the characters in your loop body, you will have an additional character in your output, with no corresponding input characters. Maybe this is the reason, why you used std::ios::exeptions in the first place.

Upvotes: 0

Related Questions