6 ms·
If we're on the subject of anti-patterns, should GOTO really never be used, in any situation? I remember writing some code in C a few years ago and I needed a
by mikevm 14y ago
If we're on the subject of anti-patterns, should GOTO really never be used, in any situation?
I remember writing some code in C a few years ago and I needed a place in a function where cleanup is performed, and in case there were errors caught in multiple places before you get to the cleanup area, I used a goto statement to jump there after printing the error message and turning on a special error flag.
How would you solve that problem without goto?
- bcoates 14y agoWithout goto, you'd either introduce a bunch of unnecessary functions or do this: init; do { stuff; if (fail) continue; morestuff; } while (0); cleanup; Which I've seen in real code released to the public. Whoever does either of those things instead of just using a goto should be flogged in the town square. edit: Other usually-bad alternatives to goto are the pyramid-of-nested-ifs or a set of running "bad" flags/enum that disables each operation downstream of the error until the cleanup is reached.
- IsaacSchlueter 14y agoYou would put the cleanup code in a separate function, and call it. I don't think there's anything wrong with using goto in such a case, though, if it makes the code more understandable.
- humbledrone 14y agoJust putting the cleanup code in a separate function doesn't solve the problem. In C, goto can be used as a kind of fall-through mechanism to clean up all of the resources a function has acquired (but no more!), in the opposite order that they were acquired. There really is no other way to accomplish this without horrible if/else nesting, which for complex functions would be pretty ridiculous. [1] http://eli.thegreenplace.net/2009/04/27/using-goto-for-error-handling-in-c/ http://eli.thegreenplace.net/2009/04/27/using-goto-for-error...
- asveikau 14y agoHaving worked in a large C code base that was occasionally tainted with this approach (rooted only because people have been told to avoid goto as dogma), I have to say that goto is a better approach to emulate try-finally or RAII in C. For one, the goto will read better as a single piece of prose, there will be no need to glance over at some other function to see the free call. Second, let's say your function has 2 allocations and a lock acquisition - that means your cleanup function needs a pointer to each, usually done with parameters. Add an extra allocation? New parameter to the cleanup function. This gets messy, fast, in a way that the goto does not.
- betterunix 14y ago"Never" is probably wrong; there are almost certainly cases where GOTO makes sense. More likely than not, though, is that if you find yourself choosing between GOTO and writing something complicated and hard to read, the problem is that your language is not expressive enough -- you are trying to do something that your language makes it hard for you to do. In the example you gave, the problem is that C lacks something like exceptions and that there is no automatic way for cleanup code to be called. In Java, you can use try...finally, and so you can put your cleanup code in the finally block, and other languages have similar constructs. Unfortunately, in many languages, throwing an exception from a finally block will cause one of the exceptions (often the first) to be "forgotten," which is probably a bad thing; this is also hard to deal with in C, however, since an error that occurs in your cleanup code would need to be signaled somehow, but you can only return one value from the function -- so would you return the error that triggered the cleanup, or the error that resulted from the cleanup?
- mikevm 14y ago>so would you return the error that triggered the cleanup, or the error that resulted from the cleanup? That's a good question. Fortunately, I don't do anything complicated in the cleanup zone - mostly closing handles and freeing memory.
- betterunix 14y ago"Fortunately, I don't do anything complicated in the cleanup zone - mostly closing handles and freeing memory" Closing handles could cause an error! Take a look at the close manpage; there are three error conditions: * The argument is a bad file descriptor * The call was interrupted by a signal * An I/O error occurred while reading or writing Reading or writing? Yes, as it turns out, closing a handle may involve I/O to perform the last synchronization of the file. It sounds like you would ignore errors caused by closing the handle, and you would signal whatever error caused the cleanup to be entered.
- mikec3k 14y agoThis is one case where a GOTO is acceptable - branching to a common exit, if it makes the code more understandable.
- kstenerud 14y agoGOTO should be used when it makes the code less repetitive, easier to follow, and less error prone. One alternative is to encapsulate the state of various resource allocations, and then call a single cleanup function at every exit point from the function that uses those resources (or take advantage of RAII, if supported by the language). However, in C this is cumbersome at best, and error prone at worst. Using GOTO for a common cleanup point is a perfectly valid use of the keyword.
- eamann 14y agoGOTO in a C/C++ world is actually a fairly efficient way to manage the exit points of your function. If you're carefully managing memory, putting all of your method cleanup code in one place and directing logic there with a GOTO is more efficient that releasing memory at several different locations within your method. At the same time, if your methods are complicated enough to possibly require multiple exit points, I'd argue that they should be refactored and broken apart a bit more.
- jfb 14y ago"How would you solve that problem without goto?" I wouldn't bother trying, at least in C.