I was reading Bjarne Stroustrups principle and practice using C++. Chapter 10.6 is about error handling of iostreams. He highlights that you should always try to recover from a fail()
state if you can while a bad()
state is generally a lost cause.
I then tried to follow this principle when making a function which sums integers seperated by whitespaces in some file:
int sum_integers(std::ifstream& is, int sum = 0)
{
if (!is) throw std::invalid_argument("Ifstream given was already in not good state");
is.exceptions(std::ios_base::badbit); // will throw error if state becomes bad
for (int num; is >> num; )
{
sum += num;
}
if (is.eof())
{
is.clear();
}
else // means state is fail()
{
is.clear();
char c; is >> c;
std::cerr << "Unvalid character '" << c << "' was encounteredn";
is.clear(std::ios_base::failbit);
}
return sum;
}
So the caller could for example deal with/ignore bad data the following way:
int main()
{
{
std::string filename = "exer1_data.txt";
std::ifstream is{filename};
try
{
int sum = sum_integers(is);
while (is.fail())
{
is.clear();
sum = sum_integers(is, sum);
}
std::cout << sum << std::endl;
}
catch(const std::invalid_argument& e)
{
std::cerr << e.what() << 'n';
}
}
}
So if exer1_data.txt
contained the following:
1 2 3 a 5
The result would still be 11.
Even though this code works it seems a little clumsy. What are some recommended improvements to the code and some better techniques for dealing with the fail()
state?