Is GOTO considered harmless when jumping to cleanu

2019-01-23 13:00发布

The goto statement has been examined at great length in several SO discussions (see this and that), and I certainly don't want to revive those heated debates.

Instead, I'd like to concentrate on a single use case of gotos and discuss its value and possible alternatives.

Consider the following code snippet, which is common in (at least my own) FSMs:

while (state = next_state()) {
        switch (state) {
                case foo:
                        /* handle foo, and finally: */
                        if (error) goto cleanup;
                        break;
                case bar:
                        /* handle bar, and finally: */
                        if (error) goto cleanup;
                        break;
                /* ...other cases... */
        }
}

return ok;

cleanup:
/* do some cleanup, i.e. free() local heap requests, adjust global state, and then: */
return error;

Swapping out the cleanup stuff in a separate function just in order to save the gotos seems awkward. On the other hand, we've been raised to condemn the use of gotos wherever possible.

My question: is my code example considered good style?
If not, are there feasible alternatives available?

Please adhere to the specific usage of goto described above. I don't want to delve into yet another discussion about the general use of goto.

10条回答
唯我独甜
2楼-- · 2019-01-23 13:33

A general principle I like to follow is that one should when possible try to write code whose flow and design fits that of the problem domain ("what the program needs to do"). Programming languages include control structures and other features which are good fits for most, but not all, problem domains. Such structures should be used when they match the program's requirements. In cases where a program's requirements are not a good match for a language's features, I prefer to focus on writing code which expresses what the program needs to do, than to contort the code to fit patterns which, while they meet the requirements of other applications, don't really meet the requirements for the program being written.

In some cases, a very natural way of translating a state machines into code, in cases where a routine will be able to not have to "exit" until a state machine has run to some form of conclusion, is to have a goto label represent each state, and use use if and goto statements for the state transitions. If the required state transitions would be a better fit for other control structures (e.g. while loops), using such loops would be better than goto statements, and using switch statements may make certain kinds of "adaptations" (e.g. having a routine perform state transition each time it's executed, rather than requiring it to immediately run to completion) much easier. On the other hand, since a switch statement is really just a "goto" in disguise, it may be cleaner to simply use a goto directly than use a switch statement to imitate one.

查看更多
小情绪 Triste *
3楼-- · 2019-01-23 13:36

Instead of extracting the cleanup logic into its own function and calling that from different places, I would consider extracting the switch statement into a separate function and returning an error code from that. In your while loop you could the check the return code and do the cleanup and return if neccessary.

If you have several resources shared between the switch and cleanup logic then I think the goto would be preferrable to passing all this state around.

查看更多
趁早两清
4楼-- · 2019-01-23 13:38

Your usage of goto is ok. It doesn't break the 2 good ways to use goto.

  1. gotos MUST go down (a few lines) in the source
  2. The innermost block of goto labels MUST contain the goto statements
查看更多
手持菜刀,她持情操
5楼-- · 2019-01-23 13:38

I'd say if the cleanup code can't be generalized, i.e. it's specific for the function it's being used in, the goto is a nice and clean way to do it.

查看更多
登录 后发表回答