I think that there are quite some occasions when the try/catch mechanism offered by C++ (and other languages) can make code clearer.
Let me go back to what I believe is the the #1 job of programmers:
To write code as simple and as clean as possible so that the code itself conveys its purpose.
We all know how much this is easier said than done. I believe that anything that could help in expressing oneself clearer is beneficial.
The first scenario that comes to mind is the need of acquire a set of resources (e.g. memory, files, connections,...). If a resource is not available, the ones previously acquired should be released. This is usually solved using nested if or using a goto to a specific cleanup section of the code. Personally I don't like neither one or the other and I believe that using try/catch would make the intent clearer.
If C had them, that is!
Actually, it turns out it's not so difficult to put together few macros to do it. C-libutl has them, they are very easy to use and only require a C99 compiler. Here is an example:
#define EXCEPTION_NOMEMORY 1
#define EXCEPTION_NORESOURCE 2
#define EXCEPTION_NOFILE 3
#define EXCEPTION_FATALERROR 5
int main(int argc, char *argv[])
{
...
try {
printf("Do something\n");
f = fopen("myfile","r");
if (f == NULL) throw(EXCEPTION_NOFILE);
printf("Continue doing\n");
}
catch (EXCEPTION_NOMEMORY) {
printf("Not enough memory\n");
}
catch (EXCEPTION_NOFILE) {
printf("Unable to find file\n");
}
...
}
I'm sure you guessed that if "myfile" doesn't exist this fragment of code will print:
Do Something
Unable to find file
So far it doesn't seem too useful: it's just a sort of goto in disguise! Or, even better, this could be handled with a simple if.
Actually, having try/catch blocks become more useful when you consider that you can throw an exception from a function and having it handled in the calling function:
void do_it(void)
{
...
m = malloc(128);
if ( m == NULL) throw(EXCEPTION_NOMEMORY);
...
}
int main(int argc, char *argv[])
{
...
try {
printf("Do something\n");
do_it();
printf("Completed\n");
}
catch (EXCEPTION_NOMEMORY) {
printf("Not enough memory\n");
}
catch (EXCEPTION_NOFILE) {
printf("Unable to find file\n");
}
catchall {
printf("Something unexpected happened\n");
}
...
}
Now, if whitin the do_it() function the system runs out of memory, the fragment will print:
Do Something
Not enough memory
A rather useful mechanism to handle herrors neatly ... or for messing everything up! As a C programmer you're used to sharp tools, I'm sure you'll find a responsible way of using it.
The catchall block at the end will be executed if an exception is thrown but is not managed earlier.
In a catch block, you can retrieve the exception code through the function thrown() (actually this is useful only in a catchall block.
Try/catch blocks can be nested but, usually, this is a rather bad idea. What is useful, instead, is the ability to pass the exception up to have it handled from the calling function like in this example:
void do_it(void)
{
...
try {
...
m = malloc(128);
if ( m == NULL) throw(EXCEPTION_NOMEMORY);
...
f = fopen("myfile","r");
if (f == NULL) throw(EXCEPTION_NOFILE);
...
}
catch (EXCEPTION_NOFILE) {
f = stdin;
free(m); // Continue in this function
}
catchall {
rethrow(); // Excpetion will be handled in the calling function
}
...
}
int main(int argc, char *argv[])
{
...
try {
printf("Do something\n");
do_it();
printf("Completed\n");
}
catch (EXCEPTION_NOMEMORY) {
printf("Not enough memory\n");
}
catch (EXCEPTION_NOFILE) {
printf("Unable to find file\n");
}
...
}
In the do_it() function, the exception NOFILE is handled directly but the exception NOMEMORY is passed to the upper try/catch block via the rethrow() function.
* * * *
The only thing that is left is to see how it is implemented. You can have a look at the utl_try.h and associated test cases ut_try.c file or read a more detailed post that explain the inner working mechanism of this flavour of try/catch.
Adding exception handling in C is a rather controversial topic. Some think that exceptions are pure evil and should never be considered, others say that those wanting to use exceptions should leave the realm of pure C and fly to C++ (or, even, Java). Others suggest that goto is a perfectly fine way to deal with exceptions.
0 comments :
Post a Comment