0

I got an exception thrown when I try to read a file since I added characters in it. But I don't understand why. Content of the file :

12 58 c 10 -105.3 c 4 -30.5 f 3 -84.7 f

There is no whitespace after the final letter. The error occur after the while read all the line, he goes in again and crash.

Thanks in advance !

#include <iostream>;
#include<fstream>
#include<string>
#include<vector>
#include<random>
using namespace std;

struct Reading {

    int hour;
    double temp;
    char t;

};

istream& operator>>(istream& is, Reading r)
{
    return is >> r.hour >> r.temp >> r.t;
}

vector<Reading> read_file()
{

    string filename{ "raw_temp.txt" };
    ifstream ifs{ filename };
    ifs.exceptions(ifs.exceptions() | ios_base::failbit);
    //if (!ifs) error("can't open input file ", filename);

    vector<Reading> r;
    while (!ifs.eof())
    {
        Reading e{};
        ifs >> e;
        if (e.t == 'c') e.temp = e.temp * 9 / 5 + 32;
        r.push_back(e);

    }
    return r;
}



int main()
try {

    vector<Reading> r;
    r = read_file();
    
}

catch (exception & e)
{
    cerr << e.what();
}

catch (...)
{
    cerr << "Unknown exception";
}
DeMoNZ
  • 1
  • can you explain a bit what you want you want to do – Sudip Ghimire Jun 20 '20 at 12:41
  • When the code reads the 5th triplet, it fails because it is out of data. The stream is set up to throw an exception when it fails. Hence, it is throwing an exception as desired. Diagnosing this problem would have been very easy within a debugger, and probably determined within a minute. Going to StackOverflow to do you debugging for you is a much slower way to debug your code. Debugging is a valuable skill that all programmers should have in their skillset. – Eljay Jun 20 '20 at 13:05
  • @Eljay Yes, but clearly the OP thinks that `while (!ifs.eof())` should protect them from that. – john Jun 20 '20 at 13:07
  • @Eljay, I'm learning c+ with the strousup's book. For the moment he doesn't really speak about the debugger. Tried to use it and effectively I saw that when it was going in the loop after it was already at the end of the file it throw out the exception. But before I did it without character and the loop worked correctly and I did not understand why just adding character would make it fail. – DeMoNZ Jun 20 '20 at 14:24
  • Doing an istream of a double will attempt to read an extra character off the stream (in the form of a peek), and if it doesn't meet the criteria of a double will be put back (or, technically, the peek isn't followed by a read) -- unless there was no character to read, which sets the EOF flag but does not set the FAIL flag. But when reading a character, it will read a single character (if available) and not peek one extra character ahead (so doesn't set the EOF flag or the FAIL flag). – Eljay Jun 20 '20 at 14:28
  • @Eljay Ok, so I change the whit to this `while (ifs >> e.hour >>e.temp >> e.t)`. It still crash, if I understand it correctly it reads my file to the last character and when it goes in again set the flag fail because there is nothing left to read ? And before because of the double put an EOF so it was working. – DeMoNZ Jun 20 '20 at 14:52
  • It shouldn't crash. It should throw an exception. – Eljay Jun 20 '20 at 15:15
  • @Eljay Yeah you're right that's what I mean. So I understood it correctly ? And I don't see how make it work correctly (Read the file without throwing exception). – DeMoNZ Jun 20 '20 at 15:21
  • Either take out this line: `ifs.exceptions(ifs.exceptions() | ios_base::failbit);` (the preferable change) or change `while (ifs >> e.hour >>e.temp >> e.t)` to `while (ifs >> e)` and add `ifs >> std::ws;` before the end of the loop. – Eljay Jun 20 '20 at 16:38
  • @Eljay Changed it to badbit. I understand it better now. Thanks for the explanations and your time ! – DeMoNZ Jun 20 '20 at 17:26

1 Answers1

1

Write your code like this

vector<Reading> r;
Reading e;
while (ifs >> e)
{
    ...
}

Then read this answer to explain why while (!ifs.eof()) is wrong

john
  • 71,156
  • 4
  • 49
  • 68
  • To trip the `ifs.eof()` check, change `ifs >> e;` to `ifs >> e >> std::ws;`. But this answer from john is a much more robust solution. (Note: also have to **not** add `ios_base::failbit` to the stream's exceptions.) – Eljay Jun 20 '20 at 13:16
  • Ok, I got it thanks ! – DeMoNZ Jun 20 '20 at 14:14