I have a program where i read values from a file. The program will then count how many numeric values were succesfully read in the range 0.0-10.0 and how many were outside of range.
The program will also write to a file each time an error occurs, for instance when the read value contains anything else than numbers.
My problem is that the program crashes after 740 values has been read, value number 741 starts with a letter so i think the issue is that my program wont catch the exceptions and just crashes the whole program. It give me no error messages in the debugger. Not while compiling and not after the crash.
What is wrong with my exceptions (in DataFileReader.cpp)?
DataFileReader.h
#ifndef DataFileReader_H
#define DataFileReader_H
#include <string>
#include <iostream>
#include <fstream>
using namespace std;
template <typename T>
class DataFileReader {
private:
string dataFileName;
string errorFileName;
ifstream dataFileStream;
ofstream errorFileStream;
public:
DataFileReader(string aDataFileName, string aErrorFileName) : dataFileName(aDataFileName), errorFileName(aErrorFileName), dataFileStream(*(new std::ifstream(""))), errorFileStream(*(new std::ofstream(""))) {};
/* pre: A file named aDataFile contains values to read. */
~DataFileReader() { dataFileStream.close(); errorFileStream.close(); }
/* post: Files are closed */
void openFiles(); // throw (runtime_error);
/* post: An input stream from the file named aDataFile and an output stream to the file named aErrorFile are opened.
If either of these operations fails a runtime_error exception is thrown. */
bool readNextValue(T &aValue);
/* pre: openFiles has been successfully called.
post: If a value has been successfully read, aValue holds that value and true is returned.
Else, the read operation encountered an end-of-file and false is returned. */
};
#endif
DataFileReader.cpp
#include "DataFileReader.h"
#include <iostream>
#include <ostream>
#include <typeinfo>
#include <istream>
#include <sstream>
template <typename T>
void DataFileReader<T>::openFiles() {
dataFileStream.open(dataFileName);
errorFileStream.open(errorFileName, ios::app);
if (!(dataFileStream.is_open() && errorFileStream.is_open()))
throw(runtime_error("Couldn't open at least one of the files."));
}
template <typename T>
bool DataFileReader<T>::readNextValue(T &aValue) {
ios_base::iostate mask = ios::eofbit | ios::failbit | ios::badbit;
dataFileStream.exceptions(mask);
while (true) {
string readValue;
try {
if (!(dataFileStream >> readValue)) // did I/O fail?
return false;
istringstream iss(readValue);
if (!(iss >> aValue)) // did parsing fail?
return false;
return iss.eof(); // was the entire value consumed?
}
catch (bad_cast &bc) {
errorFileStream << readValue << " - " << bc.what() << endl;
}
catch (ios_base::failure &eo) {
if (dataFileStream.eof())
return false;
}
}
}
DataFilter.h
#ifndef DataFilter_H
#define DataFilter_H
#include "DataFileReader.h"
template <typename T>
class DataFilter {
private:
DataFileReader<T> fileReader;
T min, max;
public:
DataFilter(DataFileReader<T> *aReader, T aMin, T aMax) : fileReader(*aReader), min(aMin), max(aMax) {};
/* pre: aReader points to an instance of DataFileReader<T> for which openFiles() has been succesfully called. */
bool getNextValue(T &aValue); // throw (range_error);
/* pre: an earlier call to getNextValue() has not returned false.
post: true is returned if aValue holds a value read from aReader. If a value could not be read, false is returned.
If a value is read but is not within the interval specified by aMin and aMax parameters to the constructor, a range_error exception is thrown. */
};
#endif
DataFilter.cpp
#include "DataFilter.h"
template <typename T>
bool DataFilter<T>::getNextValue(T &aValue) {
if (fileReader.readNextValue(aValue)) {
if (aValue > max || aValue < min)
throw(range_error("Outside of range"));
return true;
}
return false;
}
DataTestClass.cpp
#ifndef DataTestClass_H
#define DataTestClass_H
#include "DataFilter.cpp"
#include "DataFileReader.cpp"
#include <iostream>
#include <fstream>
#include <string>
#include <exception>
#include <vector>
//---------------------------------------------------------------------------
vector<double> vec;
int rangeErrorCounter = 0;
void printResults() {
double summa(0), medel(0);
vector<double>::iterator first, last, it;
first = vec.begin();
last = vec.end();
for (it = first; it != last; ++it)
summa += *it;
medel = summa / vec.size();
cout << "Numeric values read:\t" << vec.size() + rangeErrorCounter << endl;
cout << "Values outside of range:\t" << rangeErrorCounter << endl;
cout << "Total:\t\t\t" << summa << endl;
cout << "Avarage:\t\t" << medel << endl;
}
int main(int args[])
{
DataFileReader<double> dr("Values.dat", "ReadErrors.dat");
try {
dr.openFiles();
}
catch (runtime_error &rt) {
cout << "Error reading files: " << rt.what() << endl;
return 0;
}
DataFilter<double> df(&dr, 0.0, 10.0);
ofstream os("RangeErrors.dat");
if (os.is_open())
while (true) {
double value;
try {
while (df.getNextValue(value))
vec.push_back(value);
printResults();
os.close();
return 0;
}
catch (range_error) {
rangeErrorCounter++;
os << value << endl;
}
}
else
cout << "Couldn't open RangeErrors.dat" << endl;
}
#endif