1

Here is the code from cplusplus.com/reference

#include <iostream>     // std::cerr
#include <fstream>      // std::ifstream

int main () {
  std::ifstream file;
  file.exceptions ( std::ifstream::failbit | std::ifstream::badbit );
  try {
    file.open ("test.txt");
    while (!file.eof()) file.get();
    file.close();
  }
  catch (std::ifstream::failure e) {
    std::cerr << "Exception opening/reading/closing file\n";
  }

  return 0;
}

My code is very similar

int main()
{
    std::vector<int> numbers;
    std::vector<std::ifstream *> ifs;
    std::array<std::string, 3> files = {
        "f1.txt", "f2.txt", "f3.txt"
    };
    for (int i = 0; i < files.size(); ++i) {
        std::ifstream *_ifs = new std::ifstream;
        ifs.push_back(_ifs);
        ifs[i]->exceptions( std::ifstream::failbit | std::ifstream::badbit );
    }

    try {
        int n;
        std::string line;
        for (int i = 0; i < files.size(); ++i) {
            ifs[i]->open(files[i]);
            while (!ifs[i]->eof()) {
                std::getline(*ifs[i], line);
                std::istringstream iss(line);
                while (iss >> n) {
                    if (n % 3 == 0 && n % 5 == 0 && n % 7 == 0)
                        numbers.push_back(n);
                }

            }
            ifs[i]->close();
        }
    } catch (std::ifstream::failure e) {
        std::cerr << "Error reading from files: " << e.what() << std::endl;
        return 1;
    }
    for (int i = 0; i < ifs.size(); ++i)
        delete ifs[i];
    ifs.clear();
    std::cout << "Files have been read\n";

 // Do something with numbers
 // ...

}

The issue is that nothing is read. Exception is thrown almost immediatly. If I comment out failbit from exceptions everything works fine, but exceptions are not thrown when the files are missing on Windows. On Ubuntu, without failbit exceptions are thrown when the files are missing, and everything is read correctly. But with failbit on Ubuntu as well exception is thrown at the beginning of reading and nothing is read. I tried to google it. Found the example from cplusplus.com . And stackoverflow question where the answer was not to check for eof, but instead read this way while(getline(ifs, line)) { /* do something with line */ } . I tried this, and got no difference. Before I did these kinds of tasks throwing user defined classes. This time I decided to try standard library for that and it seems like I am missing something.

sasha199568
  • 1,071
  • 12
  • 30
  • The `while` should indeed loop on `getline()`, not on `eof()`. What error does your catch intercept ? – Christophe Jan 17 '16 at 21:48
  • 3
    Please provide a minimal example. It would also be interesting if the example from cplusplus.com worked as expected for you. Oh, and the `while(!in.eof())` is a classic mistake, just do some research to find out why. – Ulrich Eckhardt Jan 17 '16 at 21:48
  • Once you have it **working**. You should get the code reviewed at http://codereview.stackexchange.com – Martin York Jan 18 '16 at 00:54
  • Reading your explanation paragraph is too confusing. You need to write the example in code. Make the code do each of the things you describe in English. Then put comments in where it is not doing what you expect. – Martin York Jan 18 '16 at 01:04
  • In both cases of `while` loop the explanatory string of exception is `ios_base::clear` . I found the thing about `eof` and I tried `while (std::getline(*ifs[i], line)) { ... ` but it makes no difference. Also, if the line `while (!file.eof()) file.get();` is wrong in this case, why they wrote this code on cplusplus.com/reference? Does it mean that this web resource contains mistakes? – sasha199568 Jan 18 '16 at 20:19
  • I just tried example from cplusplus.com/reference . And it doesn't work for me either. I am surprised. This is wrong, the `while(getline(ifs, line)) { }` is also wrong. I wonder what the correct way to use `ios::exceptions` is. – sasha199568 Jan 18 '16 at 20:23

1 Answers1

1

The problem is that std::ios_base::failbit gets set when the end of the file is reached: the lines are read OK. However, once there are no further lines std::ios_base::failbit will get set: that is how the end condition is detected. As a result, only the first file is being read.

If you'd had output inside the loop reading the file you'd see that the lines are actually read. Since you filter the values read I'd guess you don't see any numbers read because none of the numbers provided matches the condition.

The check for eof() doesn't help, of course, as reading the last line will stop reading with the newline character right before reaching the end of file but it won't set std::ios_base::eofbit: the bit is only set when EOF is actually touched but that only happens with the next character read.

Since you should always check whether something was read after attempting to read, the condition while (ifs[i]->eof()) is ill-advised (and it is a good example why you should not use cplusplus.com but rather cppreference.com). Instead you should use

while (std::getline(*ifs[i], line))

You might get better results reading each of the files in their own try/catch blocks. Personally, I don't think exceptions and I/O fit well together and I have never had any production code setting an exception mask. I'd recommend staying clear of setting the exception mask for streams.

Dietmar Kühl
  • 141,209
  • 12
  • 196
  • 356