Flow controlling macros with 'goto'
Error handling is one of the rare situations when goto
is not so bad.
But if I had to maintain that code I would be very upset that goto
are hidden by macros.
So in this case goto
is OK for me but not macros.
Using goto
to go to a common error handler/cleanup/exit sequence is absolutely fine.
This code:
void func()
{
char* p1 = malloc(16);
if( !p1 )
goto cleanup;
char* p2 = malloc(16);
if( !p2 )
goto cleanup;
cleanup:
if( p1 )
free(p1);
if( p2 )
free(p2);
}
can be legally written as:
void func()
{
char* p1 = malloc(16);
char* p2 = malloc(16);
free(p1);
free(p2);
}
whether or not the memory allocations succeed.
This works because free() does nothing if passed a NULL pointer. You can use the same idiom when designing your own APIs to allocate and free other resources:
// return handle to new Foo resource, or 0 if allocation failed
FOO_HANDLE AllocFoo();
// release Foo indicated by handle, - do nothing if handle is 0
void ReleaseFoo( FOO_HANDLE h );
Designing APIs like this can considerably simplify resource management.