c++ - std::ifstream setting fail() even when no error -


using gcc 4.7.3 on cygwin 1.7.24. compiler options include: -std=gnu++11 -wall -wextra

i working on command line application , needed able load , save set of strings wrote quick wrapper class around std::set add load , save methods.

// keyset.h  #ifndef keyset_h #define keyset_h  #include <cstdlib> #include <sys/stat.h> #include <cerrno> #include <cstring>  #include <string> #include <set> #include <iostream> #include <fstream>  inline bool file_exists (const std::string& filename) { /*     utility routine check existance of file.  returns true or false,     prints error , exits status 2 on error. */     struct  stat buffer;     int     error = stat(filename.c_str(), &buffer);     if (error == 0) return true;     if (errno == enoent) return false;     std::cerr << "error while checking '" << filename << "': " << strerror(errno) << std::endl;     exit (2); }  class keyset { private:     std::string             filename;     std::set<std::string>   keys;  public:     keyset() {}     keyset(const std::string pfilename) : filename(pfilename) {}      void set_filename (const std::string pfilename) {filename = pfilename;}     std::string get_filename () {return filename;}     auto size () -> decltype(keys.size()) {return keys.size();}     auto cbegin() -> decltype(keys.cbegin()) {return keys.cbegin();}     auto cend() -> decltype(keys.cend()) {return keys.cend();}     auto insert(const std::string key) -> decltype(keys.insert(key)) {return keys.insert(key);}     void load ();     void save (); };  void keyset::load () {     if (file_exists(filename)) {         errno = 0;         std::ifstream   in (filename, std::ios_base::in);          if (in.fail()) {             std::cerr << "error opening '" << filename << "' reading: " << strerror(errno) << std::endl;             exit (2);         }          std::string     token;         if (token.capacity() < 32) token.reserve(32);          while (in >> token) keys.insert(token);          if (!in.eof()) {             std::cerr << "error reading '" << filename << "': " << strerror(errno) << std::endl;             exit (2);         }          in.clear(); // need clear flags before calling close         in.close();         if (in.fail()) {             std::cerr << "error closing '" << filename << "': " << strerror(errno) << std::endl;              exit (2);         }     } }  void keyset::save () {     errno = 0;     std::ofstream   out (filename, std::ios_base::out);      if (out.fail()) {         std::cerr << "error opening '" << filename << "' writing: " << strerror(errno) << std::endl;         exit (2);     }      (auto key = keys.cbegin(), end = keys.cend(); key != end; ++key) {         out << *key << std::endl;     }      out.close();     if (out.fail()) {         std::cerr << "error writing '" << filename << "': " << strerror(errno) << std::endl;         exit (2);     } }  #endif  // 

here's quick program test load method.

// ks_test.cpp  #include "keyset.h"  int main() {     keyset          test;     std::string     filename = "foo.keys.txt";      test.set_filename(filename);      test.load();      (auto key = test.cbegin(), end = test.cend(); key != end; ++key) {         std::cout << *key << std::endl;     } } 

the data file has "one 2 three" in it.

when go run test program, following error test program:

$ ./ks_test error closing 'foo.keys.txt': no error 

both cppreference.com , cplusplus.com close method should set fail bit on error. save method works fine, , load method works correctly if comment out error check after close. should work or have misunderstood how close supposed work? in advance.

edited clarify, fix typo's , adjust code per joachim pileborg's , konrad rudolph's comments.

edited add solution code.

you have 2 errors here: first how reading, more loop reading. eof flag not set until after tried read , read failed. instead should this:

while (in >> token) { ... } 

otherwise loop 1 time many , try read beyond end of file.

the second problem 1 notice, , depends on the first problem. since try read beyond end of file, stream set failbit causing in.fail() return true though there no real error.


Comments

Popular posts from this blog

html - How to style widget with post count different than without post count -

How to remove text and logo OR add Overflow on Android ActionBar using AppCompat on API 8? -

javascript - storing input from prompt in array and displaying the array -