So i have the following. I read in lines from a text file. Each line needs to be analysed and get the important data extracted (I wont go in the details here).
I worte a Parser class which does this job. Unforunately it can happen quite frequently, that the line data is not usable. I only find this out when read out the line in the class and analyse it. So I made a valid bit which indicates if the data is ok. At the moment I check the valid bit before grabbing the data. I was wondering if it is a better practice here to throw an exception. On the other hand i heared only throw exceptions when the case doesnt occur frequently. In my case like half the lines I analyse with the Parser class are not valid data.
Here is some simplified incomplete code how it is done now to get the idea:
struct Symbol_data { // possible data which can be extracted out of the symbolik
//Struct with the extracted data...
};
class Parse_symbol_line { //class extracts data from a line. it is possible the data is unsusable
public:
Parse_symbol_line(std::string& l);
bool is_valid() const { return valid; } //during processing the data can become unusable
Symbol_data get_symbolic_data() { return sym_data; }
private:
//Private Methods here which extract and analyse the line in many steps
void read_data_from_line();
void analyze_raw_comment();
void mask_out_device_id();
void analyze_device_id();
void mask_out_vessel();
void create_symbol_data();
bool valid; // if in valid dont use the data
Symbol_data sym_data;
};
//constructor calls all the steps to read out the data out of the line
//it is possible after each step, that the line is not valid and therefore doesnt need more checks
Parse_symbol_line::Parse_symbol_line(std::string& l)
:valid{ true }, EA{ true }, line{ l }, sym_data{ Symbol_data{} }
{
read_raw_data_from_line();
if (!valid) return; //dont continue if data is invalid anyway
analyze_raw_comment();
if (!valid) return;
mask_out_device_id();
if (!valid) return;
analyze_device_id();
if (!valid) return;
mask_out_vessel();
if (!valid) return;
create_symbol_data();
if (!valid) return;
}
//another class provides the lines to the parse class and gets the data from it
void Compute_Symbols::read_symbolic()
{
std::ifstream ifs{ in_sym_fname };
if (!ifs) throw std::runtime_error("void Compute_Symbols::read_symbolic(); symbolic file could not be opened\n");
for (std::string line; std::getline(ifs, line);) {
Parse_symbol_line psl{ line };
if (psl.is_valid()) {
//continue work with the data
}
else if (!psl.is_valid()) {
//dont use the data
}
}
}
std::optional
facility in C++ to return either an empty result, indicating invalid, or a valid result.