5 ms·
I've found goto to be a good way of dealing with exceptions in low-level C. For example: void* foo() { int handle = get_some_handle(); if (
by thegeomaster 10y ago
I've found goto to be a good way of dealing with exceptions in low-level C. For example:
void* foo() {
int handle = get_some_handle();
if (handle < 0) {
goto fail;
}
void* something = some_function(handle);
if (something == NULL) {
goto free_handle;
}
void* something_else = some_other_function(something);
if (something_else == NULL) {
goto free_something;
}
return something_else;
free_something:
free_something(something);
free_handle:
free_handle(handle);
fail:
return NULL;
}
I've seen this pattern frequently in the Linux source code. I think this is an example of a case where usage of goto improves readability and reduces errors.
- lubonay 10y agoI've also seen extensive use of gotos for exception handling in C. After the knee-jerk reaction ("...but but Dijkstra!") I came to appreciate it as a useful idiom.
- cestith 10y agoTo be fair, Dijkstra said "harmful", not "forbidden". He was also talking about encouraging structured procedural programming rather than a game of Who's Clever Enough to Follow the Spaghetti. We do things that are harmful all the time, in limited appropriate situations. Cutting into your abdomen is harmful, but a skillfully used surgeon's scalpel can fix a bigger problem. That's not license to go roll around on a pile of jagged, rusty steel scrap. Missing sleep is harmful, but if you do it once in a while to keep your job or to escape a nighttime flash flood then it's helpful. Dijkstra was intending to set the norm from which people should mindfully and occasionally deviate. The point wasn't to ban the use of labelled jumps entirely.
- ape4 10y agoThis looks fine to me. I wonder if C/C++ could be improved by introducing a new keyword `bail` which is the same as `goto` but is only allowed to jump to the bottom of the function. That way, codebases can outlaw `goto` but keep `bail`.
- 72deluxe 10y agoAre you looking for "return"? With C++ you can ensure that you have your destructors do the tidy up, e.g. a messy example struct cleaner { cleaner(string *toCleanup) : m_x(toCleanup) { } ~cleaner() { delete m_x; m_x = nullptr; } };
- ape4 10y agoYup, C++ has autocleanup. Of course if you are using fopen() instead something more modern you'll need to fclose(). Adding a new keywords to C is a long shot. Perhaps compilers could detect non-cleanup use of goto and give it a warning.
- int_19h 10y agoA typical C++ codebase I'm working on these days would have scope guards implemented via macros, such that you can do e.g.: FILE* f = fopen(...); SCOPE_GUARD({ fclose(f); }); This is mainly used for one-off calls to some native API, where writing a proper RAII wrapper for the managed resource is not worth it.
- krylon 10y agoIn a previous job where I wrote C code, I had a macro named "bail" that pretty much did that: log an error message, then jump to the cleanup section of the function.
- flukus 10y agoWouldn't it be better to have some sort of linter tool do this? Why create a more specific language construct when you already have one?
- yekim 10y agoYes - a thousand times yes! The goto has gotten a bad rap over the years because of Dijkstra's paper. And that paper has unduly influenced a lot of incorrect thinking. There are valid use cases for goto, and this is certainly one of them. I use it all the time like the example above. Particularly because it makes my life so much easier when developing and debugging embedded C code across various tool chains, some of which have less functionality than others. [edit - correct typo on Ed's name]
- Watabou 10y agoJust curious, not a C developer by any means, but why wouldn't you use a function here instead of a goto? I'm confused how goto would reduce error/improve readability in that example. Again, not criticizing, genuinely want to know.
- emptybits 10y agoSimply: a goto never returns while a function call returns to where it was called from. So specifically in the example above, if you called failure-handling functions instead of using goto's then when the function returned you would continue execution on the next line after the function call. In the example above, that's clearly not what you want. Now you could add some else's after the function calls to prevent execution from continuing. i.e. to get to the appropriate step in the free_* sequence at the bottom, but that starts to look messy. So I have to admit (not being a goto-lover), the above example reads very nicely. It conforms to the "gotos might be okay if they only jump forward" rule of thumb I've heard.
- popee 10y agoGKH somewhere explained that they accept gotos that don't go back (leads to mess) only gotos that jump forward in function. Nice rule.
- ArkyBeagle 10y agoI'd much rather see that as a state machine.
- flukus 10y agoHow common is it to add "exception macros"? Something like: "error(handle, "could not open handle", free_something)"