6

I don't understand what is throwing the exception here with my input file stream. I have done almost the exact thing before without any problems.

std::string accnts_input_file = "absolute_path/account_storage.txt";
std::string strLine;
std::ifstream istream;
istream.exceptions( std::ifstream::failbit | std::ifstream::badbit );

try
{
    istream.open( accnts_input_file.c_str() );

    while( std::getline( istream, strLine ) )
    {
        std::cout << strLine << '\n';
    }

    istream.close();
}
catch( std::ifstream::failure &e )
{
    std::cerr << "Error opening/reading/closing file" << '\n'
              << e.what()
              << std::endl;
}

I only have it printing the line it reads right now to try and track the error. It reads the file, line by line and prints them, then it throws the exception. The exception says basic_ios::clear, which i don't understand. I think it is ifstream::failbit that is throwing the exception, because when I only set ifstream::badbit it doesn't throw an exception, but I can't figure out why. I've also tried 'while( !istream.oef() )', and most other methods, instead of 'while( std::getline( istream, strLine ) )', but i keep getting the same error.

I'm sure it's probably something obvious I'm missing, but any help would be appreciated. Thanks

anacy
  • 399
  • 4
  • 14

3 Answers3

8

From this std::getline reference:

...
a) end-of-file condition on input, in which case, getline sets eofbit.
...
3) If no characters were extracted for whatever reason (not even the discarded delimiter), getline sets failbit and returns.

That means that on end of file condition, the function sets both eofbit and failbit. And as you asked to get an exception when failbit is set, the library throws an exception.

Some programmer dude
  • 400,186
  • 35
  • 402
  • 621
  • 1
    What would be the better method of doing this? – anacy Jun 25 '14 at 21:03
  • Looks like a bug to me or at least bad design on getline() – Slava Jun 25 '14 at 21:09
  • 1
    @Slava I think the design of the standard library behaviors usually can be considered well thought, and may intend covering more use cases as you see here from an immediate concrete point. Also IMHO (have to check from the docs) failbit, just indicates the last extraction operation on a `std::istream` failed, thus the design of `getline()` (or any other extraction operation) to set it for the EOF case is absolutely fine. – πάντα ῥεῖ Jun 25 '14 at 22:05
2

When you try to read from the stream but there is nothing left to read the read operation will fail (= no characters are inserted in the variable denoted by the 2nd argument of getline) the failbit is set and in your case an exception is thrown.

Using while(!ifstream.eof()) will only help if your file doesn't end for example with a newline character. The eofbit is only set if the end of the stream is reached, i.e. every content of the stream was read out. But if the file ends on a newline character the read operation will fail without having the eofbit set before.

a_guest
  • 34,165
  • 12
  • 64
  • 118
  • How do I get around this? What would be the better method of doing this? – anacy Jun 25 '14 at 21:01
  • After catching the exception you can check whether the eofbit is set or not. If it is you know that everything's fine and you don't have to exit your program (or whatever you want to do in case of I/O failure). – a_guest Jun 25 '14 at 21:06
  • @anacy looks like you need to manually check that failbit is set without eofbit and treat that as error condition – Slava Jun 25 '14 at 21:10
  • @Slava - What would be a good design to do something like this? – anacy Jun 25 '14 at 21:15
  • @anacy probably write your own getline, that will intercept std::ifstream::failure and rethrow it only when eofbit is not set. – Slava Jun 25 '14 at 21:19
  • Should i just not even throw failbit as an exception at all? – anacy Jun 25 '14 at 21:20
  • @anacy try solution from my answer – Slava Jun 25 '14 at 21:26
  • @anacy _'Should i just not even throw failbit as an exception at all?'_ IMHO this would be the easiest (and most _"natural_") solution. Why did you think to need exceptions at all for this? – πάντα ῥεῖ Jun 25 '14 at 21:36
  • @πάντα ῥεῖ -- i don't really know. I just saw an example of it on cplusplus.com, and figured it would be a good way to catch any errors. I thought it failbit was thrown then something had gone wrong – anacy Jun 25 '14 at 21:41
  • @anacy _'I thought it failbit was thrown then something had gone wrong'_ In some sense that's true, when `getline()` cannot extract more characters, but that's well indicated by it's return value. – πάντα ῥεῖ Jun 25 '14 at 21:43
0

One of the possible solutions:

bool mygetline( std::istream &in, std::string &s )
{
    try {
        return std::getline( in, s );
    }
    catch( std::ifstream::failure & )
    {
         if( !in.eof() ) throw;
         return false;
    }
}

std::string accnts_input_file = "absolute_path/account_storage.txt";
std::string strLine;
std::ifstream istream;
istream.exceptions( std::ifstream::failbit | std::ifstream::badbit );

try
{
    istream.open( accnts_input_file.c_str() );

    while( mygetline( istream, strLine ) )
    {
        std::cout << strLine << '\n';
    }

    istream.close();
}
catch( std::ifstream::failure &e )
{
    std::cerr << "Error opening/reading/closing file" << '\n'
              << e.what()
              << std::endl;
}
Slava
  • 43,454
  • 1
  • 47
  • 90