Question

Since I started programming I was taught to never use 'goto' if it can be avoided. I, however, came across a case where I think goto is the easiest way to keep this code clean.

My code looks like the following example:

// code within a for-loop
// ...
// ...
try{
      if(!ifstream.open())
          throw special_exception;

      A_EXCEPTION_HANDLED:
//...
//...
}
catch(special_exception ex)
{
  // trying to fix the error here
  if(error_is_fixed)
     goto A_EXCEPTION_HANDLED;

  // else clean up and show error message
};

This example is inside a nested loop and I need to be sure that the code following the throw is executed properly so I would have to write a lot of overhead to start the iteration, in which the exception was thrown, again. Would this case be considered as fair use of goto or is it as bad style as jumping out of loops etc. ?

Was it helpful?

Solution

I think based on your description the code can be rewritten like this:

for ( /* usual stuff */ )
    try{
          if(!ifstream.open())
              throw special_exception;
    } catch (const special_exception&) {
        if (/* "can't handle the truth!" */) {
            // clean up & show error message
            break;
        }
    }
    // OK, continue
}

OTHER TIPS

The concept of retrying after an exception is not unheard of (e.g.: Common Lisp implements something like that as part of the language).

However, do you really need an exception there? If you (as opposed to a library) throw the exception, and there is only one place where it is thrown (as your example shows), couldn't you simply write something like this?

if(!ifstream.open()) {
    // trying to fix the error here
    if(!error_is_fixed) {
        throw really_unrecoverable();
    }
    // else let it continue normally
}

If this logic gets repeated too often, I can see the justification of the exception and retrying the algorithm with goto. But if it happens only once or twice, I would write the code for recovery inline (perhaps with a helper function).

Using goto to implement a loop is not a fair use of goto.

To implement a loop in C++, use a loop construct.

Regarding the details of your concrete case, please do supply them.

In the example you give I would argue that the use of the goto to traverse two blocks is indeed bad style.

Now the use of 'goto' generates all kinds of unwarrented hysteria but in this case the reason that it's bad style is very clear:

Readers of your code may reasonably expect that once an exception handler has been invoked, something really bad has happened that prevents the current code context from continuing. If the ifstream is expected to exist and does not, this is an exceptional case and an exception is warranted. However, if the attempt to open the stream is simply a test which could reasonably be expected to fail, then this is not an exceptional thing. In this case, don't use an exception at all. Under these circumstances, a better way to express your intent might be like this:

for(/* usual stuff */)
    while (!ifstream.open()) {
      if (!attemptRemedialAction()) {
        throw really_bad_thing_happened_exception;
      }
    }
  // do things with ifstream, 
  // including goto statements if they express your intent elegantly
}

// allow the outer context or the caller to deal with the exceptional case of non-recovery

Style is exactly how it sounds like. Some people like one, others like another. As a developer you will work with many people and have to deal with their different styles.

The really important thing is not to preach one style over another, but to keep the style consistent within a project. If this project uses goto then stick with it, and write your parts accordingly. Because other devs will expect jumps and will look for them.

(as a side note there are systems where only one exception is allowed to exist at any given time, eg Symbian and other EPOC derivatives, so what we're seeing here might be a necessity not a style)

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top