What is the best way to manage resources for a C program. Should I use a nested if structure or should I use goto statements?
I am aware there is a lot of taboo about goto statements. However, I think it is justified for local resource clean up. I have supplied two samples. One compares a nested if structure and another uses goto statements. I personally find the goto statements make the code easier to read. For those who might argue that the nested if prompt better structure, imagine if the datatype was something other than a char*, like a Windows handle. I feel that the nested if structure would get out of hand with a series of CreateFile functions or any other function that takes large quantities of parameters.
This article demonstrates that local goto statements create RAII for C code. The code is neat an easy to follow. Imagine that as a series of nested if statements.
I understand that goto is taboo in many other languages because their exists other control mechanisms like try/catch etc, however, in C it seems appropriate.
#include <stdlib.h>
#define STRING_MAX 10
void gotoExample()
{
char *string1, *string2, *string3, *string4, *string5;
if ( !(string1 = (char*) calloc(STRING_MAX, sizeof(char))) )
goto gotoExample_string1;
if ( !(string2 = (char*) calloc(STRING_MAX, sizeof(char))) )
goto gotoExample_string2;
if ( !(string3 = (char*) calloc(STRING_MAX, sizeof(char))) )
goto gotoExample_string3;
if ( !(string4 = (char*) calloc(STRING_MAX, sizeof(char))) )
goto gotoExample_string4;
if ( !(string5 = (char*) calloc(STRING_MAX, sizeof(char))) )
goto gotoExample_string5;
//important code goes here
gotoExample_string5:
free(string4);
gotoExample_string4:
free(string3);
gotoExample_string3:
free(string2);
gotoExample_string2:
free(string1);
gotoExample_string1:
}
void nestedIfExample()
{
char *string1, *string2, *string3, *string4, *string5;
if (string1 = (char*) calloc(STRING_MAX, sizeof(char)))
{
if (string2 = (char*) calloc(STRING_MAX, sizeof(char)))
{
if (string3 = (char*) calloc(STRING_MAX, sizeof(char)))
{
if (string4 = (char*) calloc(STRING_MAX, sizeof(char)))
{
if (string5 = (char*) calloc(STRING_MAX, sizeof(char)))
{
//important code here
free(string5);
}
free(string4);
}
free(string3);
}
free(string2);
}
free(string1);
}
}
int main(int argc, char* argv[])
{
nestedIfExample();
gotoExample();
return 0;
}
I would also like to quote Linus Torvalds on goto statements inside the Linux Kernel.
And sometimes structure is bad, and
gets into the way, and using a “goto”
is just much clearer.For example, it is quite common to
have conditionals THAT DO NOT NEST.In which case you have two
possibilities
use goto, and be happy, since it doesn’t enforce nesting
This makes the code more readable,
since the code just does what the
algorithm says it should do.duplicate the code, and rewrite it in a nesting form so that you can
use the structured jumps.This often makes the code much LESS
readable, harder to maintain, and
bigger.The Pascal language is a prime example
of the latter problem. Because it
doesn’t have a “break” statement,
loops in (traditional) Pascal end up
often looking like total shit, because
you have to add totally arbitrary
logic to say “I’m done now”.
Is goto acceptable for resource management? Should I use nested if statements or is there a better way?
Update: Examples of Good Gotos In C
Cleanup using
gotohas the advantage that it’s less error-prone. Having to free each and every resource allocated on each and every return point can lead to someone someday missing some cleanup when doing maintenance work.That said, I’ll quote Knuth’s “Structured Programming with goto Statements”:
and Knuth’s quote of Dijkstra in that same paper: