Use GOTO or not? [closed]

2019-01-03 09:29发布

Currently I am working on a project where goto statements are heavely used. The main purpose of goto statements is to have one cleanup section in a routine rather than multiple return statements. Like below:

BOOL foo()
{
   BOOL bRetVal = FALSE;
   int *p = NULL;

   p = new int;
   if (p == NULL)
   {
     cout<<" OOM \n";
     goto Exit;
   }

   // Lot of code...

Exit:
   if(p)
   {
     delete p;
     p = NULL;
   }
   return bRetVal;
}

This makes it much easier as we can track our clean up code at one section in code, that is, after the Exit label.

However, I have read many places it's bad practice to have goto statements.

Currently I am reading the Code Complete book, and it says that we need to use variables close to their declarations. If we use goto then we need to declare/initialize all variables before first use of goto otherwise the compiler will give errors that initialization of xx variable is skipped by the goto statement.

Which way is right?


From Scott's comment:

It looks like using goto to jump from one section to another is bad as it makes the code hard to read and understand.

But if we use goto just to go forward and to one label then it should be fine(?).

标签: c++ goto
30条回答
做自己的国王
2楼-- · 2019-01-03 09:50

You should read this thread summary from the Linux kernel mailing lists (paying special attention to the responses from Linus Torvalds) before you form a policy for goto:

http://kerneltrap.org/node/553/2131

查看更多
Rolldiameter
3楼-- · 2019-01-03 09:51

Since this is a classic topic, I will reply with Dijkstra's Go-to statement considered harmful (originally published in ACM).

查看更多
戒情不戒烟
4楼-- · 2019-01-03 09:51

Using "GOTO" will change the "logics" of a program and how you enterpret or how you would imagine it would work.

Avoiding GOTO-commands have always worked for me so guess when you think you might need it, all you maybe need is a re-design.

However, if we look at this on an Assmebly-level, jusing "jump" is like using GOTO and that's used all the time, BUT, in Assembly you can clear out, what you know you have on the stack and other registers before you pass on.

So, when using GOTO, i'd make sure the software would "appear" as the co-coders would enterpret, GOTO will have an "bad" effect on your software imho.

So this is more an explenation to why not to use GOTO and not a solution for a replacement, because that is VERY much up to how everything else is built.

查看更多
我想做一个坏孩纸
5楼-- · 2019-01-03 09:54

The only two reasons I use goto in my C++ code are:

  • Breaking a level 2+ nested loops
  • Complicated flows like this one (a comment in my program):

    /* Analysis algorithm:
    
      1.  if classData [exporter] [classDef with name 'className'] exists, return it,
          else
      2.    if project/target_codename/temp/classmeta/className.xml exist, parse it and go back to 1 as it will succeed.
      3.    if that file don't exists, generate it via haxe -xml, and go back to 1 as it will succeed.
    
    */
    

For code readability here, after this comment, I defined the step1 label and used it in step 2 and 3. Actually, in 60+ source files, only this situation and one 4-levels nested for are the places I used goto. Only two places.

查看更多
姐就是有狂的资本
6楼-- · 2019-01-03 09:54

I think using the goto for exit code is bad since there's a lot of other solutions with low overhead such as having an exit function and returning the exit function value when needed. Typically in member functions though, this shouldn't be needed, otherwise this could be indication that there's a bit too much code bloat happening.

Typically, the only exception I make of the "no goto" rule when programming is when breaking out of nested loops to a specific level, which I've only ran into the need to do when working on mathematical programming.

For example:

for(int i_index = start_index; i_index >= 0; --i_index)
{
    for(int j_index = start_index; j_index >=0; --j_index)
        for(int k_index = start_index; k_index >= 0; --k_index)
            if(my_condition)
                goto BREAK_NESTED_LOOP_j_index;
BREAK_NESTED_LOOP_j_index:;
}
查看更多
聊天终结者
7楼-- · 2019-01-03 09:55

There are basically two points people are making in regards to gotos and your code:

  1. Goto is bad. It's very rare to encounter a place where you need gotos, but I wouldn't suggest striking it completely. Though C++ has smart enough control flow to make goto rarely appropriate.

  2. Your mechanism for cleanup is wrong: This point is far more important. In C, using memory management on your own is not only OK, but often the best way to do things. In C++, your goal should be to avoid memory management as much as possible. You should avoid memory management as much as possible. Let the compiler do it for you. Rather than using new, just declare variables. The only time you'll really need memory management is when you don't know the size of your data in advance. Even then, you should try to just use some of the STL collections instead.

In the event that you legitimately need memory management (you have not really provided any evidence of this), then you should encapsulate your memory management within a class via constructors to allocate memory and deconstructors to deallocate memory.

Your response that your way of doing things is much easier is not really true in the long run. Firstly, once you get a strong feel for C++ making such constructors will be 2nd nature. Personally, I find using constructors easier than using cleanup code, since I have no need to pay careful attention to make sure I am deallocating properly. Instead, I can just let the object leave scope and the language handles it for me. Also, maintaining them is MUCH easier than maintaining a cleanup section and much less prone to problems.

In short, goto may be a good choice in some situations but not in this one. Here it's just short term laziness.

查看更多
登录 后发表回答