I have a setup that looks like this.
class Checker
{ // member data
Results m_results; // see below
public:
bool Check();
private:
bool Check1();
bool Check2();
// .. so on
};
Checker is a class that performs lengthy check computations for engineering analysis. Each type of check has a resultant double that the checker stores. (see below)
bool Checker::Check()
{ // initilisations etc.
Check1();
Check2();
// ... so on
}
A typical Check function would look like this:
bool Checker::Check1()
{ double result;
// lots of code
m_results.SetCheck1Result(result);
}
And the results class looks something like this:
class Results
{ double m_check1Result;
double m_check2Result;
// ...
public:
void SetCheck1Result(double d);
double GetOverallResult()
{ return max(m_check1Result, m_check2Result, ...); }
};
Note: all code is oversimplified.
The Checker and Result classes were initially written to perform all checks and return an overall double result. There is now a new requirement where I only need to know if any of the results exceeds 1. If it does, subsequent checks need not be carried out(it’s an optimisation). To achieve this, I could either:
- Modify every CheckN function to keep check for result and return. The parent Check function would keep checking m_results. OR
- In the Results::SetCheckNResults(), throw an exception if the value exceeds 1 and catch it at the end of Checker::Check().
The first is tedious, error prone and sub-optimal because every CheckN function further branches out into sub-checks etc.
The second is non-intrusive and quick. One disadvantage is I can think of is that the Checker code may not necessarily be exception-safe(although there is no other exception being thrown anywhere else). Is there anything else that’s obvious that I’m overlooking? What about the cost of throwing exceptions and stack unwinding?
Is there a better 3rd option?
I don’t think this is a good idea. Exceptions should be limited to, well, exceptional situations. Yours is a question of normal control flow.
It seems you could very well move all the redundant code dealing with the result out of the checks and into the calling function. The resulting code would be cleaner and probably much easier to understand than non-exceptional exceptions.
Change your
CheckX()functions to return thedoublethey produce and leave dealing with the result to the caller. The caller can more easily do this in a way that doesn’t involve redundancy.If you want to be really fancy, put those functions into an array of function pointers and iterate over that. Then the code for dealing with the results would all be in a loop. Something like:
Edit: I had overlooked that you need to call any of N
SetCheckResultX()functions, too, which would be impossible to incorporate into my sample code. So either you can shoehorn this into an array, too, (change them toSetCheckResult(std::size_t idx, double result)) or you would have to have two function pointers in each table entry:(And, no, I’m not going to attempt to write down the correct syntax for a member function pointer’s type. I’ve always had to look this up and still never ot this right the first time… But I know it’s doable.)