开发者

multiple return statements or a "goto end;"

What is better stylewise/readability?

I have a loop that reads input and does different things according to the input, and when an error occurs, I need a simple return;. Example:

while( get_input() )
{
    if( input == "somethingcool" )
    {
        if( !process_somethingcool() )
            return; // <-- a couple of these
    }
    //...
    else // bad input, error handling is fancier than this,开发者_如何学Go but irrelevant to the question
        return;
}
return;

So should I replace the individual return;s with a goto end; and place a label end: right above the last return in the example above or not? I am not in need of "use RAII" because nothing is allocated in the if blocks. Both ways would be identical in all senses of the word, except for the style/readability/performance?

I would suppose performance is identical, but just to be sure: is it?


For C, goto is reasonable (it's used widely in the Linux kernel) as you can enhance readability with a single point of return.

For C++, because you have the possibility of anything throwing an exception, you implicitly have multiple points of return so you should always use the RAII model with multiple returns.


Are you trying to start a religious war?

Seriously, there are occasionally places where a goto is the best choice. In twenty years, I've seen around 3 or 4. Multiple returns are not necessarily evil, but if you have to repeat a lot of cleanup code then they become pretty messy.

Very often, you can refactor the code to make such a choice unnecessary. It is hard to make specific suggestions without seeing your code, but maybe something like this:

void f()
{
   bool bDone=false;
   while (!bDone && get_input())
   {
      if (input == "cool")
      {
         process_cool();
         bDone = true;
      }
      else if (input == "unfinished")
      {
         process_something();
      }
      else
      {
          // error
          bDone = true;
      }
   }
}

A big help in refactoring is to make sure you don't have dozens of lines inside the loop. If you have a lit of work to do, break it into functions and call a small number of functions from within the while loop.

Remember that a single function should only do one thing.

Another approach that is highly recommended is to use exceptions to handle error conditions, but it is bad style to use an exception if you have just finished processing, so this might not completely solve your problem.

If you are still confused, consider posting a more realistic chunk of code and we may be able to suggest how best to handle things.

Good Luck!


Personally, I like to keep the content of any blocks as small as possible. One line, calling out to another function is ideal (after Bob Martin's Clean Code).

I'd go with an option you haven't proposed:

while(get_input()) {
    if(!process_input(input)) {
         break;
    }
}

Where process_input would select the appropriate process_... function, returning whatever that returns, or false if there is bad input.


Just return when you want to return. The C++ language can handle that, and it is the most intuitive way to write your code.

In some languages, cleanup has to be done at the use site, and so it may be a good idea to centralize the "cleanup" phase in a single block that you "goto". In C, this idiom is common.

In C++, resources are cleaned up by themselves in their destructors when they go out of scope. And so at the use site, nothing needs t obe done, and the easiest, cleanest and least error-prone solution is to just have multiple return statements.


Multiple return statements are actually good style and almost always produce cleaner code than trying to have a single return point. gotos are pretty useless in C++ as (apart from their other problems) they can't jump over initialisations, which possibly forces you to initialise things away from their point of use, which is also bad style.


Style and readability would lead me to use exceptions to handle error conditions. How is your caller to know whether your method was invoked correctly?

That said: goto shouldn't be used for this; return is the far better option. If you need to do anything at the end of your routine, regardless of why it dropped out - then you should throw exceptions and use a catch block.


return is generally preferred to goto; usually, detractors of labels are unable to come up with any actual argument to support their dogma.1

However, your case is more clear-cut: why would you pick the goto? Both solutions are equivalent, except that the goto requires you to write end: just before the end of the function, taking up space and looking ugly for no reason.

Therefore, out of the two options presented, I'd recommend the returns. That said, I'd also recommend seriously considering the other suggestions given in responses to this question (exceptions, and limiting the "nestiness" of your conditionals).


1 Or, if they do, it's usually something along the lines of "goto leaves your objects hanging", which is not true (as per 6.6/2 in the C++0x FDIS). goto does not break the RAII model.


The goto End; is nice in part because of readability but also because if you realize later there are things that need to happen before you close the function, freeing memory or releasing resources for example, you can centralize that process instead of copy pasting it.


Actually, its not advisable to use goto. It generates problems in readability of the code. Better use a break; statement where you want to leave the loop and return at the end of the code. That's the standard procedure.

while( get_input() )
{
    if( input == "somethingcool" )
    {
        if( !process_somethingcool() )
            break; // <-- a couple of these
    }
    //...
    else // bad input, error handling is fancier than this, but irrelevant to the question
        break; //although its better if you handle it somehow here.
}
return;


Why not structure your code using "guard clauses" (by reversing the logic) instead of the nested ifs. Then the whole question of using goto becomes moot.

while( get_input() )
{
    if( input != "somethingcool" )
    {
        return; //handle error
    }
    if( !process_somethingcool() )
        return; //handle error
    }
}
return; //success


Neither. You should refactor the code into something readable and maintainable. Every case I've seen (and I've seen a lot) where the programmer has needed a goto, and most of the cases where he's needed multiple returns (and all cases where the return has been nested in a loop) would have be better solved by refactoring the code into separate, simpler functions, each of which had a single return at the end of the function. (Multiple returns are sometimes justified for very simple functions; e.g. I'll use them if the only statement in the function is a switch, and every case ends with a return.)


IMHO use multiple returns and do not use goto. Those who use goto, also set dogs on fire.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜