fstream flags are not updated correctly

lgeyer
2012-06-13
2013-06-06
  • lgeyer
    lgeyer
    2012-06-13

    I'm currently using i686-w64-mingw32-gcc-4.7.0-release-win32_rubenvb and I've run into serious troubles with fstream, as state flags are not updated.

    > systeminfo
    Microsoft Windows 7 Ultimate
    6.1.7601 Service Pack 1 Build 7601
    x64-based PC
    [01]: Intel64 Family 6 Model 37 Stepping 2 GenuineIntel ~2534 MHz     
    > cat main.cpp
    #include <iostream>
    #include <fstream>
         
    using namespace std;
         
    int main(int argc, char *argv[])
    {
        fstream sout;
        sout.open("test", ios::in | ios::out | ios::trunc);
        
        // loop does not terminate, as no flags are set
        while (sout) {
            string str;
            getline(sout, str);
            cout << str << sout.rdstate() << endl;
        }
        
        return 0;
    }
         
    > g++ --version
    g++ (rubenvb-4.7.0) 4.7.0
    > mingw32-make main
    g++     main.cpp   -o main
         
    > main.exe
    0
    0
    0
    ...
    

    Any thoughts on this?

     
  • rubenvb
    rubenvb
    2012-06-13

    Your C++ is not good.

    First, I don't know what you're trying to do. You open a file "test" with an input/output fstream, but specify std::truncate. You don't check if your call to std::getline works before outputting the result.

    I'm going to assume you are reading lines from a file, and write a small demo of what you should do in this case:

    #include <iostream> // std::cout, std::cerr
    #include <fstream> // std::ifstream
    #include <string> // std::getline, std::string
    int main(int argc, char *argv[])
    {
       std::ifstream stream;
       stream.open("test.txt");
       
       if(!stream)
       {
           std::cerr << "Rrror opening file.\n";
           return 1;
       }
       std::string result;
       while(std::getline(stream, result))
       {
           std::cout << result << "\nStream state: " << stream.rdstate() << "\n";
       }
    }
    

    This creates an input fstream, opens a file, checks if the open operation works, and uses std::getline in the loop predicate, which is the foolproof way of checking if the input operation worked. If this doesn't fail, it outputs the line read from the file "test.txt", which in my case contained:

    line1
    line 2
    

    And this would give the output:

    line1
    Stream state: 0
    line 2
    Stream state: 0
    

    If this is not what you're trying to do, I suggest Stackoverflow.com for C++ questions. You will get fast and correct answers if your question is clear.

     
  • lgeyer
    lgeyer
    2012-06-13

    Thanks for the response.

    It is actually a simplified example of a larger codebase just to show the problem. It originally arose when building Qt5 with i686-w64-mingw32-gcc-4.7.0-release-win32_rubenvb, more specifically the configure application.

    See http://qt.gitorious.org/qt/qtbase/blobs/master/tools/configure/configureapp.cpp#line3187

    In the end it is valid C++, and the configure application as well as the example I've posted works correctly on gcc-4.7 (Ubuntu/Linaro 4.7.0-7ubuntu3) 4.7.0 and MSVC (eofbit and failbit set), so the problem is local to MinGW.

     
  • rubenvb
    rubenvb
    2012-06-17

    I'm still not convinced this code does what you want.

    You are also missing #include <string> for std::getline. The code you linked to opens an fstream without ever checking the stream state after the call to open.

    Also: there's no need to getline every string, you should just seek to the beginning and do "cout << sout".

     
  • lgeyer
    lgeyer
    2012-06-17

    The problem is that the stream flags do not get set correctly - this has primarily nothing to do with specific code (quality).

    I've created another two examples, which both work as expected on gcc-4.7 (Ubuntu/Linaro 4.7.0-7ubuntu3) 4.7.0 and MSVC (eofbit and failbit set), but not on i686-w64-mingw32-gcc-4.7.0-release-win32_rubenvb (and the 64 bit equivalent).

    #include <iostream>
    #include <fstream>
    #include <string>
    using namespace std;
    int main(int argc, char *argv[])
    {
        fstream sout;
        sout.open("non_existent_file", ios::in);
        
        // failbet should be set, isn't
        cout << sout.rdstate(); 
        return 0;
    }
    
    #include <iostream>
    #include <fstream>
    #include <string>
    using namespace std;
    int main(int argc, char *argv[])
    {
        char c;
        fstream sout;
        sout.open("existent_file", ios::in);
        
        // should not enter loop on open error, as failbit should be set
        // should exit on eof, as eofbit should be set, isn't
        while(sout.good())
        {
            sout.get(c);
            if(sout.good())
                cout << c;
        }
        return 0;
    }
    
     
  • rubenvb
    rubenvb
    2012-06-18

    Thanks for posting examples that are more clear in intent.

    Your first example:
    http://ideone.com/9HW1e
    It gives the exact same behavior when I compile and run it with any of my release builds (this means GCC 4.5.3, 4.6.3, 4.7.0 and 4.7.1).

    Your second example written in a file "test.cpp", opening the file "test.cpp" echos back the contents like I expect.
    You can simplify that immensely though:

    #include <iostream>
    #include <fstream>
    #include <string>
    using namespace std;
    int main(int argc, char *argv[])
    {
      fstream sout;
      
      sout.open("test.cpp", ios::in);
      if(!sout) // handle file open error
        cerr << "Error opening file.\n";
      
      // should not enter loop on open error, as failbit should be set
      // should exit on eof, as eofbit should be set, isn't
      char c;
      while(sout.get(c))
      {
        cout << c;
      }
    }
    

    So I looked at your original example again:
    1) You specify "std::ios_base::trunc" which discards the file contents, leading to
    2) trying to output the result of a failed read.

    It prints "6" on my machine, which is exactly what it outputs on my Arch VM with GCC 4.7.0.

     
  • lgeyer
    lgeyer
    2012-06-19

    That's quite interesting. I've set up a fresh installation of Windows 7 x64 in a virtual machine - and all toolchains work correctly.

    So this seems to be a problem local to this machine.

    Any ideas what this could cause resp. how to track down the problem?