I’m trying to write a function in C to solve a math problem. In that function, there are several steps, and each step needs to allocate some memory with the size depending on the calculation results in previous steps (so I can’t allocate them all at the beginning of the function). The pseudo code looks like:
int func(){
int *p1, *p2, *p3, *p4;
...
p1 = malloc(...);
if(!p1){
return -1; //fail in step 1
}
...
p2 = malloc(...);
if(!p2){
free(p1);
return -2; //fail in step 2
}
...
p3 = malloc(...);
if(!p3){
free(p1);
free(p2);
return -3; //fail in step 3
}
...
p4 = malloc(...);
if(!p4){
free(p1);
free(p2);
free(p3); /* I have to write too many "free"s here! */
return -4; //fail in step 4
}
...
free(p1);
free(p2);
free(p3);
free(p4);
return 0; //normal exit
}
The above way to handle malloc failures is so ugly. Thus, I do it in the following way:
int func(){
int *p1=NULL, *p2=NULL, *p3=NULL, *p4=NULL;
int retCode=0;
...
/* other "malloc"s and "if" blocks here */
...
p3 = malloc(...);
if(!p3){
retCode = -3; //fail in step 3
goto FREE_ALL_EXIT;
}
...
p4 = malloc(...);
if(!p4){
retCode = -4; //fail in step 4
goto FREE_ALL_EXIT;
}
...
FREE_ALL_EXIT:
free(p1);
free(p2);
free(p3);
free(p4);
return retCode; //normal exit
}
Although I believe it’s more brief, clear, and beautiful now, my team mate is still strongly against the use of ‘goto’. And he suggested the following method:
int func(){
int *p1=NULL, *p2=NULL, *p3=NULL, *p4=NULL;
int retCode=0;
...
do{
/* other "malloc"s and "if" blocks here */
p4 = malloc(...);
if(!p4){
retCode = -4; //fail in step 4
break;
}
...
}while(0);
free(p1);
free(p2);
free(p3);
free(p4);
return retCode; //normal exit
}
Hmmm, it seems a way to avoid the use of ‘goto’, but this way increases indents, which makes the code ugly.
So my question is, is there any other method to handle many ‘malloc’ failures in a good code style? Thank you all.
Ask your teammate how he would re-write this sort of code:
And ask how he would generalize it to
nresources. (Here, “grabbing a resource” could mean locking a mutex, opening a file, allocating memory, etc. The “free on NULL is OK” hack does not solve everything…)Here, the alternative to
gotois to create a chain of nested functions: Grab a resource, call a function that grabs another resource and calls another function that grabs a resource and calls another function… When a function fails, its caller can free its resource and return failure, so the releasing happens as the stack unwinds. But do you really think this is easier to read than the gotos?(Aside: C++ has constructors, destructors, and the RAII idiom to handle this sort of thing. But in C, this is the one case where
gotois clearly the right answer, IMO.)