...
In this revised version, we have used a goto-chain in replacement of each individual return segment. If there is no error, control flow will fall through to the SUCCESS label, release all of the resources and return 0RET_SUCCESS
. In the case of an error, the return value will be set to RET_ERROR
, control flow will jump to the proper failure label, and the appropriate memory resources will be freed released before returning an error.
Code Block | ||
---|---|---|
| ||
// ... assume the same struct as above ... #define RET_SUCCESS 0 #define RET_ERROR -1 int do_something(void){ FILE *fin; object_t *obj1, *obj2; int ret_val = RET_SUCCESS; // Initially assume a successful return value fin = fopen("some_file", "r"); if (fin == NULL){ ret_val = RET_ERROR; goto FAIL_FIN; } obj1 = malloc(sizeof(object_t)); if (obj1 == NULL){ ret_val = RET_ERROR; goto FAIL_OBJ1; } obj2 = malloc(sizeof(object_t)); if (obj2 == NULL){ ret_val = RET_ERROR; goto FAIL_OBJ2; } // ... more code ... SUCCESS: // Free everything and return normally fclose(fin); free(obj1); free(obj2); return 0; FAIL_OBJ2: // Otherwise, free only the objects inwe orderallocated free(obj1); FAIL_OBJ1: fclose(fin); FAIL_FIN: return -1ret_val; } |
The benefits of this method are that the code is cleaner and we prevent the rewriting of similar code upon every function error.
...