I am writing a unit test for file read using qtestlib, C++ (clang LLVM version 8.0). I have the following code for reading a file line by line.
std::ifstream infile;
try {
infile.open(path.c_str());
std::ios_base::iostate exceptionMask = infile.exceptions() | std::ios::failbit;
infile.exceptions(exceptionMask);
} catch (std::ios_base::failure& e) {
// print the exception
qDebug() << "Exception caught: " << QString::fromStdString(e.what());
}
try {
std::string line;
while (std::getline(infile, line)) {
// print the line
qDebug() << QString::fromStdString(line);
}
} catch (std::ios_base::failure& e) {
qDebug() << "Exception caught: " << QString::fromStdString(e.what());
}
The issue:
The above code reads all the lines in the file and prints it. But after printing the last line, it throws an exception and prints the following,
Exception caught: "basic_ios::clear"
I followed many threads, but could not find the solution to this. Why am I getting this error?
After you have read and printed all the lines, the while (std::getline(infile, line))
will still try to read another line. If it fails totally - zero characters read - it sets failbit
to signal its failure.
The odd part of the error message is that, despite its name, basic_ios::clear
can be used to set the failure bit and will also throw an exception if you have enabled the same bit with exceptions
.
Take a look on documentation of std::getline. Scetion about setting flags:
failbit
The input obtained could not be interpreted as a valid textual representation of an object of this type. In this case, distr preserves the parameters and internal data it had before the call. Notice that some eofbit cases will also set failbit.
The last sentence is a bit fuzzy, but can explain observed behavior.
I did some experiments and found the pattern. First I've corrected your code this way:
try {
std::string line;
while (std::getline(infile, line)) {
// print the line
qDebug() << QString::fromStdString(line);
if (infile.eof()) {
return;
}
}
} catch (std::ios_base::failure& e) {
qDebug() << "Exception caught: " << QString::fromStdString(e.what());
}
Now if input file ends with empty line I get an exception, if last line doesn't end with "\n" return
breaks a loop.
So falbit is set if you are trying to read stream which already reached end of stream. Without "if" check you are always doing this reading and always get an exception.
For last line empty I have some clues, but have not idea how to explain it nicely. First have to check behavior of other platforms/compilers.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With