#define DEFER(EXPR) for(int _tmp=1; _tmp; _tmp=0,(EXPR))
Example: char * data = malloc(32);
DEFER(free(data))
{
// do stuff
} #define DEFER(EXPR) for(int _tmp=1; _tmp; _tmp=0,(EXPR))
Example: char * data = malloc(32);
DEFER(free(data))
{
// do stuff
}Alternatively you might be able to use nested functions to guard against a stray return but that's not standard.
static unsigned int __deferDepth = 0;
#define RETURN return
#define return ((__deferDepth == 0) ? RETURN : break do_return)
#define DEFER(EXPR) \
__label__ do_return; \
for(int _tmp = 1; _tmp; _tmp = (do { \
__deferDepth += 1; \
EXPR; \
__deferDepth -= 1; \
break; \
do_return: \
RETURN; \
}while(0);))
Nested DEFERs could get hairy, though (do you need a stack of __returnNotBreak values?), and there probably are issues if EXPR contains some nested loops with break or return.Regardless, this isn’t C. Statement expressions (and __label_) are a gcc* extension, and if you’re willing to go there, __attribute__((cleanup)) seems the wiser route.
Most of the challenge in writing code with a single return seems to come from the fact that I'm not used to doing it. Of course, sometimes it leads to heavily nested control flow, although I'm not sure yet whether or not I mind that. It does certainly simplify reasoning about control flow though, especially in large functions.
That all being said, I'd still rather just have defer.
For instance parameter validation is one instance where I think an early return is very much warranted. There you typically have no cleanup to do since it's effectively the prelude of the function.
Regarding nested error handling, I prefer the "goto fail" pattern. Some people are opposed to the use of goto as a matter of principle but I think in this case it's fine. It's effectively the poor man's RAII when you don't have destructors.
That's what the assert statement is for; checking pre- and postconditions.