Re: Invalid parameter handling
On Mar 27, 5:02 am, Kaba <REkalleMOunderscoreVErutane...@hotmail.com>
wrote:
Consider the std::vector and its member functions operator[]() and at().
Off-indexing the operator[]() results in undefined behaviour, probably
in an assertion in debug mode and in a crash in release mode. The 'more
secure' at() results in an exception when off-indexing. Everyone will
probably agree that such defined behaviour is better than the undefined
behaviour with operator[]().
You've lost me there. If there is an error in the code, the
prefered behavior, except in a few exceptional cases, is to stop
the program as quickly and as brutally as possible, while
executing as little code as possible after the error has been
detected. My own code is replete with assert's, and they're
active in the delivered code.
If I detect an error in the code, the last thing I want to do is
to continue running.
Hands on your hearts, how many times have you catched an off-index
exception? That's right, never or almost never. This is because the
indexing operation is a very low-level activity. This is not a surprise
since one of std::vector's roles is to act as a smart replacement for a
native array.
Also, no doubt, because I tend to code carefully, and avoid such
errors, and because the ones I do miss are caught in code
review.
Now consider the consequences of an off-indexing. In case of operator[],
a havoc is wreaked. In case of at(), because the off-indexing is rarely
catched, the reaction is also probably wrong and will shutdown at least
part of the program. Should you say that "Well that's your fault since
you did not catch the exception."?
No you should not. How do you react correctly to an exception that
effectively says "you have a bug somewhere"? You don't. In my opinion,
it is very wrong to throw an exception here. Exceptions are a handy
tool, but one should keep in mind that:
* they should only be used in a level high enough so that their handling
doesn't litter the program.
* they should only be used if they can be reacted upon.
You've just reached the same conclusion many of us have.
Exceptions are very useful in certain cases, but they aren't a
silver bullet, or even a universal answer for anything.
std::vector's at() fails both of these criterions.
It depends. I can imagine cases where an out of bounds index is
not a programming error, but an exceptional (but expected) case
resulting from e.g. user input. Personally, in such cases, I
would prefer to make this clear, by testing the index and
throwing an exception explicitly, before accessing the array,
but I suppose that using at() is a valid alternative in such
cases.
My concentration here is on std::vector since that is familiar to all of
the users of C++. However, the underlying problem is a more general one:
"What can you do to robustly handle invalid parameters?". Anyway, what
is robust in this situation?
It really depends on the context in which the program is to run.
I think that for most programs, "robust" means "get the hell out
of there, as soon as possible." There are exceptions, however;
in a computer game, it might be preferable to continue doing
something.
To gain insight to that, consider the user
of your program:
You have succesfully created a word processing program which your
customer is using to create his to-be-bestseller book. He's in the
middle of an inspiration storm and continuously works for an hour
without remembering to save. Then, he clicks on a menu, and instead of
the "help" row, accidentally hits the "about" box. Now, deep inside the
word processing program the menu is (of course) using a std::vector to
hold its callback functions for the different choices. But unfortunately
it was somehow left one element too short and the "about" row doesn't
have an associated callback function!
So what happens? The word processing program indexes the std::vector
using the at() function. But now at() correctly throws an exception,
which isn't catched at all because it is such a low-level thing and the
word processor eventually delivers a report to the writer that "there
has been an internal error and the program has to be shut down". If
there are no autosave features or such, the work is all lost.
There's a fundamental design error here. Any program which
might be used for critical work must be designed with the idea
that it can crash. Even without a programmer error, someone
pulls the power cord, or the computer catches fire, or whatever.
Every editor I use makes frequent backups, automatically; when I
request editing a file, it checks if a backup for that file is
present, and if so, asks if I want to restore from the backup.
(Nothing new here: this was present in vi at least 20 years
ago.)
This is not robust. But by this example we see what would be robust:
that we could keep the program running as long as possible.
Not really. If you have an error in the program, what do you
know about its internal state. Suppose you do throw an
exception. Stack unwinding calls destructors, and as a result
of the error, one of the destructors overwrites all of the text
with gibberish, and then saves it. As a user, I'd much rather
have "internal error", and an offer to restore to the last saved
state when I next try to edit the file.
[...]
Speaking of practice, I have used the techniques given in the article in
my own 1.5mb library with great success. Handling invalid parameters
creates a kind of a secure web which assures you that "even if invalid
parameters are given, the program does something sensible". Sensible
usually means doing nothing, and that propagates up as much as it has
that effect. But after taking these techniques into use, I see crashes
very rarely. Instead, I get a no-op, and a descriptive warning message
to my log what went wrong, and still the program keeps continuing.
In an incorrect state, so doing the wrong thing.
--
James Kanze (GABI Software) mailto:james.kanze@gmail.com
Conseils en informatique orient?e objet/
Beratung in objektorientierter Datenverarbeitung
9 place S?mard, 78210 St.-Cyr-l'?cole, France, +33 (0)1 30 23 00 34
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]