I'm working on a school project and the teacher asked us to free all resources at program's termination.
I'm struggling to find a way to write more readable and/or less code to manage that, specifically considering this is made more complex by the fact that different exit points will probably have a different set of resources to free.
The simplest and most messy solution seems to be this(exit points are represented as "some_sys_call" calls that return -1):
char *a = malloc(1);
if(some_sys_call() == -1){
free(a);
return -1;
}
//b is needed until the end
char *b = malloc(1);
if(some_sys_call() == -1){
free(a);
free(b);
return -1;
}
//c is needed until the end
char *c = malloc(1);
//a is no longer needed from here on, so it's freed right away
free(a);
if(some_sys_call() == -1){
free(b);
free(c);
return -1;
}
//Exit point when there are no errors
free(b);
free(c);
return 0;
This doesn't seem very appealing for obvious reasons: you need to write a lot of code especially when you have a lot of resources, making the code bloated with frees and less readable. Of course you can't simply write a macro or function that frees all the resources and call it at each exit point, like this:
#define free_all free(a); \
free(b); \
free(c);
You could technically define different macros/functions for each set of frees:
#define free_1 free(a);
#define free_2 free(a); \
free(b);
...
This would make the "actual" code more readable but would still require you to write a lot of different macros and doesn't seem to me like a good solution either.
Is this considered a common problem? How is this usually handled?
This is a well known practice in C, although if it is best or not is disputable
char *a = malloc(1);
char *b = NULL;
char *c = NULL;
int ret = 0;
if(some_sys_call() == -1) {
goto fail;
}
b = malloc(1);
if(some_sys_call() == -1) {
goto fail;
}
c = malloc(1);
if(some_sys_call() == -1) {
goto fail;
}
goto cleanup;
fail:
ret = -1;
cleanup:
free(c);
free(b);
free(a);
return ret;
The same but a bit shorter (inspired by proxyres /resolver_win8.c:338):
char *a = malloc(1);
char *b = NULL;
char *c = NULL;
int ret = 0;
if(some_sys_call() == -1) {
goto fail;
}
b = malloc(1);
if(some_sys_call() == -1) {
goto fail;
}
c = malloc(1);
if(some_sys_call() == -1) {
fail:
ret = -1;
}
free(c);
free(b);
free(a);
return ret;