I've also seen goto appropriately used to break out of deeply nested for loops. Now, you may ask when it's appropriate to use deeply nested for loops, and that's a whole different story.
I use goto all the time, but only for one coding pattern. It's a very powerful pattern, which allows me to do memory cleanup completely on a per-function basis:
int abc(void *ctx) {
int rc = -1;
if (outcome_of_first() != SUCCESS) {
my_log(MY_LEVEL, "Log my error");
goto over;
}
if (outcome_of_second() != SUCCESS) {
my_log(MY_LEVEL, "Log my error");
goto over;
}
...
rc = 0;
over:
if (something_allocated != NULL)
free(something_allocated);
if (something_else_allocated != NULL)
free(something_else_allocated);
return rc;
}
Fair enough that GOGO works elegantly for a hard-coded DFA. But as hard-coded automata get larger, they get harder to read. A general-purpose solution which runs automata defined more concisely elsewhere (e.g., in a DSL) is generally preferable because it will end up being more flexible and maintainable.
Not as performant, no. But the complaint about GOTO is that it tends to be a hallmark of less-maintainable code. This example falls right in with that complaint on account of being a less-maintainable way to write code.
4 comments
[ 3.5 ms ] story [ 15.6 ms ] threadWhen writing software manually, this is rarely the best choice, but for automatic generation of code, this is very powerful.
Do never listen to the stupidities that are said to sell code quality checking software.
int abc(void *ctx) { int rc = -1;
over: if (something_allocated != NULL) free(something_allocated);Not as performant, no. But the complaint about GOTO is that it tends to be a hallmark of less-maintainable code. This example falls right in with that complaint on account of being a less-maintainable way to write code.