In C I just used goto - you put a cleanup section at the bottom of your code and your error handling just jumps to it.
#define RETURN(x) result=x;goto CLEANUP
void myfunc() {
int result=0;
if (commserror()) {
RETURN(0);
}
.....
/* On success */
RETURN(1);
CLEANUP:
if (myStruct) { free(myStruct); }
...
return result
}
The advantage being that you never have to remember which things are to be freed at which particular error state. The style also avoids lots of nesting because it returns early. It's not as nice as having defer but it does help in larger functions.One small nitpick: you don't need check before `free` call, using `free(NULL)` is fine.
defer is a stack, scope local and allows cleanup code to be optically close to initialization code.
The disadvantage is that a "goto fail" can easily happen with this approach. And it actually had happened in the wild.
This looks like a recipe for disaster when you'll free something in the return path that shouldn't be freed because it's part of the function's result, or forget to free something in a success path. Just write
result=x;
goto cleanup;
if you meant result=x;
goto cleanup;
At least then you'll be able to follow the control flow without remembering what the magic macro does.But you have to give this cleanup jump label a different name for every function.
> The advantage being that you never have to remember which things are to be freed at which particular error state.
You also don't have to remember this when using defer. That's the point of defer - fire and forget.