quote:
Original post by Kensai
1) exception handling is for exceptional situations, not flow control. think deeply on this
quote:
1) exception handling is for exceptional situations, not flow control. think deeply on this
quote:
1) exception handling is for exceptional situations, not flow control. think deeply on this
I copied it three times because it's worth repeating three times.
You should see no decrease in performance if your code contains exceptions that are not being called. People who say they see a decrease in performance are not following Kansai's rule #1.
You WILL see larger source code. This is because whenever you put a "throw" in your code, stack objects must be unwound. However, this code is only executed in
exceptional situations , and should not execute in the normal flow of your program.
We wrote a script parsing program here that controls simulation hardware. The script language had about 50 built-in functions, with optional parameters to most, etc., etc. About 10 times in each function you saw this code:
if (num_args < REQUIRED_NUM_ARGS){ sprintf (s, "Error in OPEN_HARDWARE: requires %d arguments", REQUIRED_NUM_ARGS); log->write (s, LOG_LEVEL_CRITICAL); m_error = true; return false; // caller checks return value}
This same block of code was copied around about 300 times. Did the user get uniform error reporting? No. Sometimes the function name was included, sometimes not. Every time a function was called, it used its return value to indicate an error (which could have been used for much more useful things).
When I took over the project, one of the things I did was replace all of these statements to throw exceptions. You just have the sprintf line, and then a throw runtime_exception (s). Then, in the main loop that parses and calls each script line, I caught the exception. This allowed my code to work like this:
try{ script->*pFunc (args); // call script function}catch (exception &e){ sprintf (s, "Error in file %s, line %d, function %s: %s", script->cur_file, script->cur_line, script->cur_func, e.what ()); log->write (s, LOG_LEVEL_CRITICAL); error = 1; return;}catch (...){ sprintf (s, "Unknown error in file %s, line %d, function %s", script->cur_file, script->cur_line, script->cur_func); log->write (s, LOG_LEVEL_CRITICAL); error = 1; return;}
To my users, all the errors have the same format with the script file, line and function name followed by reason for error. Not only that, but now my functions look much cleaner:
if (num_args < REQUIRED_NUM_ARGS){ sprintf (s, "requires %d arguments", REQUIRED_NUM_ARGS); throw invalid_argument (s);}
And if your functions call other functions, there's no need to check return codes and return all the way out on error; all of that is done automatically by C++ EH.
Proper use of exceptions makes your code more readable, more maintainable, more robust and does not cause any decrease in performance. The action of throwing an exception is slow in itself, but exceptions should not be thrown unless the program would otherwise crash--and who cares how fast you crash?
edit--sorry, I always put a 'code' at the end rather than a '/code' accidentally.
Edited by - Stoffel on February 24, 2001 1:54:49 PM