Comment by mkl
14 days ago
Nested ifs are my preference:
bool function_with_cleanup(void) {
int *buffer1 = NULL;
int *buffer2 = NULL;
FILE *file = NULL;
bool success = false;
// Allocate first resource
buffer1 = malloc(sizeof(int) * 100);
if (buffer1) {
// Allocate second resource
buffer2 = malloc(sizeof(int) * 200);
if (buffer2) {
// Open a file
file = fopen("data.txt", "r");
if (file) {
// Do work with all resources...
fclose(file);
success = true; // Only set to true if everything succeeded
}
free(buffer2);
}
free(buffer1);
}
return success;
}
Much shorter and more straightforward.
One-time loops with break also work if you're not doing the resource allocation in another loop:
bool function_with_cleanup(void) {
int *buffer1 = NULL;
int *buffer2 = NULL;
FILE *file = NULL;
bool success = false;
do { // One-time loop to break out of on error
// Allocate first resource
buffer1 = malloc(sizeof(int) * 100);
if (!buffer1) {
break; // Error, jump to cleanup
}
// Allocate second resource
buffer2 = malloc(sizeof(int) * 200);
if (!buffer2) {
break; // Error, jump to cleanup
}
// Open a file
file = fopen("data.txt", "r");
if (!file) {
break; // Error, jump to cleanup
}
// Do work with all resources...
success = true; // Only set to true if everything succeeded
} while(false);
// Free resources in reverse order of acquisition
if (file) fclose(file);
free(buffer2); // free() is safe on NULL pointers
free(buffer1);
return success;
}
Still simpler to follow than goto IMHO. Both these patterns work in other languages without goto too, e.g. Python.
Nested if, aside from being awful, doesn't scale.
And break is extremely thin sugar on top of go-to.