首页 > 解决方案 > 捕获异常的问题

问题描述

我有一个程序,我从文件中读取值。然后程序将计算在 0.0-10.0 范围内成功读取了多少数值,以及有多少超出了范围。

每次发生错误时,程序也会写入文件,例如当读取的值包含除数字以外的任何内容时。

我的问题是程序在读取 740 个值后崩溃,值编号 741 以字母开头,所以我认为问题是我的程序不会捕获异常并且只会使整个程序崩溃。它在调试器中没有给我任何错误消息。不是在编译时,也不是在崩溃之后。

我的异常有什么问题(在 DataFileReader.cpp 中)?

数据文件读取器.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

数据文件读取器.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;
        }
    }
}

数据过滤器.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

数据过滤器.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;
}

数据测试类.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

标签: c++parsingexception

解决方案


推荐阅读