Search code examples
c++file-iowhile-loopistream

while(f) not behaving as expected


I am facing problem with this c++ code in codeblocks... here is the code:

#include<iostream>
#include<fstream>
using namespace std;

class test {
   int i;
   float j;
public:
   void getdata() {
       std::cout<<"\nenter i and j:";
       std::cin>>i>>j;
   }
   void putdata() {
       std::cout<<"\ni="<<i<<"\tj="<<j;
   }
};
int main()
{
    test ob,ob1;
    fstream f;
    f.open("dil.txt",ios::out|ios::binary);
    for(int i=0;i<5;i++)
    {
       ob.getdata();
       f.write((char *)& ob,sizeof(ob));
    }
    f.close();
    f.open("dil.txt",ios::in|ios::binary);
    f.seekg(0);
    while(f) {
       f.read((char *)& ob1,sizeof(ob1));
       ob1.putdata();
    }
    f.close();
    return 0;
}

The output after entering the details is coming:

i=2     j=2.3
i=3     j=3.4
i=4     j=4.5
i=5     j=5.6
i=6     j=6.7
i=6     j=6.7

so,my question is why the last statement is getting repeated?...please help


Solution

  • The code while(f) is implicitly casting f to a bool by calling std::basic_ios::operator bool on f.

    In this case operator bool will return true as long as there were no errors reading that stream.

    When your code has reached the end of the file, the loop test will call operator bool and it will return true because, so far, there have been no errors. It then calls f.read which triggers an error because it is trying to read past the end of the file.

    Because the stream is now in an error state, f.read will not update the buffer passed to it, so the buffer will still have the data returned in the previous call. This is why the last value is repeated.

    Now, when the loop test is performed again, operator bool will return false because the stream is in an error state and the loop will terminate.

    I see this mistake a lot in beginner C++ code. I did the same thing until I learned how iostreams work. I think this tends to happen when someone is coming from a language where it's idiomatic to test on some sort of end-of-file function before reading. Most of the time, I've seen an iostream's eof function being used as the loop test. That causes the same problem because eof does not tell you that you've reached the end of the stream. It tells you that you've tried to read past it.

    C++ iostreams are designed so that you can do your loop test on the result of the read operation.