What is the advantage of using goto in this code?

static gboolean gst_fd_src_start (GstBaseSrc * bsrc) { GstFdSrc *src = GST_FD_SRC (bsrc); src->curoffset = 0; if ((src->fdset = gst_poll_new (TRUE)) == NULL) goto socket_pair; gst_fd_src_update_fd (src, -1); return TRUE; /* ERRORS */ socket_pair: { GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ_WRITE, (NULL), GST_ERROR_SYSTEM); return FALSE; } } 

why did someone use goto socket_pair; I do not understand why this mechanism is used? why don't we just write an error message there and not come back?

Note: this is the gstreamer plugin code

+4
source share
8 answers

In large procedures, a function may have several points that must goto handle the error code. This procedure should be considered in the context of writing in accordance with the code conventions that define the general form for error handling.

It is true that goto should be considered dangerous, but for a language like C that does not have exception handling, it might be the least bad option for handling errors.

+11
source

In the code that you indicated, in principle, there is no good reason for this.

In general, you sometimes see the label โ€œerror handlerโ€ at the bottom of the function, if the function needs to make several errors upon failure (for example, not only return an error code), or for coding standards, one return is required for each function (some government work does this ) The main body code uses goto to trigger error handling when necessary. This is kind of poor thing try/catch/finally .

So for example:

 int someNiftyFunction() { int rv = 0; acquireSomeResource(); if (some_failure_condition) { rv = -1; goto error_out; } if (some_other_failure_condition) { rv = -2; goto error_out; } if (yet)_another_failure_condition) { rv = -3; goto error_out; } setUpSuccessStuff(); exit: cleanUpSomeResource(); return rv; error_out: setUpFailureStuff(); logSomeValuableInfo(); goto exit; } 

Basically, everything from acquireSomeResource() to the exit: label is roughly a try block, the exit: label is finally , and error_out is catch. Very rude.: -)

+7
source

if it's an old-fashioned C that doesn't have exception handling built into the language structure, this idiom is a good way to mimic it.

Imagine there were 10 early exit conditions. if you want to compose each of them as a return statement, you will need to repeat the call in GST_ELEMENT_ERROR 10 times, while using goto means that you only need to put it once.

it is obvious that in this case there is only 1 condition for early exit, but it is usually better to implement this idiom completely through the code, and not just the functions that need it

+5
source

This is the usual way in C to separate error handling and clear them from regular code. In other languages, you would use some sort of structured exception instead. This is a cleaner way to do this in C. In more complex situations, the advantage becomes more noticeable. In many cases, the error handling / cleaning code must be called from different places. Refactoring this does not make much sense, I think goto not evil if you use it in C for this. In other programming languages โ€‹โ€‹that have better mechanisms, you should of course avoid using goto ...

+3
source

This can be done to have common code for handling socket errors. In this particular case, it is required only in one case, and in this case it may not be necessary to use goto , but only for reasons of consistency (general approach to the entire code base).

+2
source

As mentioned above, if you look only at this function, it is pointless. However, if you have a function with many error situations and some cleaning problems before exiting the function, this kind of programming is inevitable, otherwise your code will increase for all errors or some cleaning problems. To make programming more structured, sometimes all functions can be written with goto destructor, like the code you mention.

+2
source

goto has no advantages (except for output nested loops). Some people may argue that error handling is separated by a form of logic. But I would write this as:

 static gboolean gst_fd_src_start (GstBaseSrc * bsrc) { GstFdSrc *src = GST_FD_SRC (bsrc); src->curoffset = 0; if ((src->fdset = gst_poll_new (TRUE)) == NULL) { GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ_WRITE, (NULL), GST_ERROR_SYSTEM); return FALSE; } gst_fd_src_update_fd (src, -1); return TRUE; } 
0
source

As pointed out in other answers, in a simple example this does little; its advantages are more obvious when there are many resources to access, and many error conditions. This pseudo code demonstrates this:

 boolean allocate_resources (ObjectA **a, ObjectB **b, ObjectC **c) { *a = allocate_a(); if (*a == NULL) { LOG_ERROR("failed to allocate A"); goto fail0; } *b = allocate_b(); if (*b == NULL) { LOG_ERROR("failed to allocate B"); goto fail1; } *c = allocate_c(); if (*c == NULL) { LOG_ERROR("failed to allocate C"); goto fail2; } return true; fail2: release_b(*b); fail1: release_a(*a); fail0: return false; } 

Notice how this function works atomically, as seen from the outside - when it returns, either all resources are allocated, or none of them, avoiding leaks.

Compare this with one possible version that uses nesting instead of goto:

 // Bad style. Don't do this. boolean allocate_resources (ObjectA **a, ObjectB **b, ObjectC **c) { *a = allocate_a(); if (*a == NULL) { LOG_ERROR("failed to allocate A"); } else { *b = allocate_b(); if (*b == NULL) { LOG_ERROR("failed to allocate B"); } else { *c = allocate_c(); if (*c == NULL) { LOG_ERROR("failed to allocate C"); } else { return true; } release_b(*b); } release_a(*a); } return false; } 

This version is much harder to read. The goto version first shows what the main execution path will be; this is not the case here. Nesting makes the code more difficult to read, and also discards horizontal space.

I hope I have not ruined it, and it is functionally equivalent to the first example; I suggest you try to prove to yourself that this is equivalent, and see for yourself how difficult it is to work.

0
source

Source: https://habr.com/ru/post/1379468/


All Articles