65

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(?).

Legorooj
  • 2,646
  • 2
  • 15
  • 35
anand
  • 11,071
  • 28
  • 101
  • 159

35 Answers35

60

I am not sure what do you mean by clean up code but in C++ there is a concept called "resource acquisition is initialization" and it should be the responsibility of your destructors to clean up stuff.

(Note that in C# and Java, this is usually solved by try/finally)

For more info check out this page: http://www.research.att.com/~bs/bs_faq2.html#finally

EDIT: Let me clear this up a little bit.

Consider the following code:

void MyMethod()
{
    MyClass *myInstance = new MyClass("myParameter");
    /* Your code here */
    delete myInstance;
}

The problem: What happens if you have multiple exits from the function? You have to keep track of each exit and delete your objects at all possible exits! Otherwise, you will have memory leaks and zombie resources, right?

The solution: Use object references instead, as they get cleaned up automatically when the control leaves the scope.

void MyMethod()
{
    MyClass myInstance("myParameter");
    /* Your code here */
    /* You don't need delete - myInstance will be destructed and deleted
     * automatically on function exit */
}

Oh yes, and use std::unique_ptr or something similar because the example above as it is is obviously imperfect.

Tamas Czinege
  • 118,853
  • 40
  • 150
  • 176
  • It helps in cleanup code , plus it also helps in avoiding multiple return paths from routine that are some times very difficult to track . – anand Dec 18 '08 at 20:47
  • 6
    ALien01: Multiple return paths and multiple, "goto end of function" are exactly equal in difficulty to track. – Brian Dec 18 '08 at 21:48
  • The above code is in C, so C++ methods doesn't seem to apply – chmike May 24 '09 at 10:31
  • Oops, checked again and it is indeed ment to be C++. So indeed better make use of RIAA. – chmike May 24 '09 at 10:34
  • 2
    There are no "object references" here. – Lightness Races in Orbit Jun 19 '13 at 23:06
  • Sometimes when efficiency counts we don't want to use RAII, because it would mean unecessary copy of a list of pointers for example. Instead we just want to make sure they are either returned or deleted in case of failure. – VinGarcia Jul 20 '16 at 12:59
60

I've never had to use a goto in C++. Ever. EVER. If there is a situation it should be used, it's incredibly rare. If you are actually considering making goto a standard part of your logic, something has flown off the tracks.

Gene Roberts
  • 2,192
  • 3
  • 17
  • 16
  • 2
    short and simple answer, but I think it nails it. goto's are in the language for a reason, certainly, but if you actually consider using them, there's a 99.9% chance that you're Doing It Wrong. Don't write your code as if it falls into the 0.01% case because it probably doesn't. – jalf Dec 18 '08 at 21:42
  • 44
    Sometimes you need a goto to break from nested loops. – rlbond Apr 27 '09 at 17:53
  • 18
    @rlbond: While this is often repeated, it's just as often proven to be false. (This is Tagged `C++`. C++ has inlining. So you can always use a `return` instead of a `goto`.) – sbi Oct 30 '09 at 23:05
  • 1
    @ribond: "want" != "need". Been there, done that - and as a rule of thumb, each `goto` seems to increase your code maintenance costs by 30%. Yes, yes, *you* understand the code *now*. That doesn't say anything about the programmer who will be modifying it in two years. – Piskvor left the building Jun 17 '10 at 07:58
  • By the way check libpng/freetype/libjpeg/vorbis how they USE goto where performance is critical! goto CAN SLIGHTLY increase performance. Also, please not that using gotos in ENCRYPTION code.... is... REQUIRED if you want to fool hackers / reverse engineers EVEN MORE. So just kill this goto-phobia! – Петър Петров Jun 11 '14 at 10:55
  • 3
    @ПетърПетров why would encryption code need to be hidden from reverse engineering? Rely on the protocol to be secure and not [security through obscurity](http://en.wikipedia.org/wiki/Security_through_obscurity). If you really must embed a secret in client code then use a proper obfuscation tool. – RJFalconer Jun 19 '14 at 12:46
  • 3
    ...and obfuscation tools often convert code paths to ASM jump-flooded gibberish, and goto is nothing different than a assembly jump anyway :) – Петър Петров Jun 23 '14 at 08:46
  • @rlbond I agree with you in most cases but sometimes you just cant use a return statement. In this case you can either use boolean logic or a single goto to break out of the nested loops. – Zachary Kraus Sep 19 '14 at 15:24
  • 41
    There is no better solution for breaking nested loops than goto. Period. Yes, you can return. Yes, you can use some obscure bools. Yes, you can even abuse try/catch *lol*. But each of this is worse and makes either the code less readable or is bad for performance. And if you really find a double loop with a loop exit label directly after it too confusing, you'd better get another job. – user2328447 Oct 11 '14 at 22:19
  • 14
    @user2328447 There **most certainly are** better ways to break out of loops than `goto` how about `return`, `continue` or `break` for sensible loop control? If you really need finer control than that you should seriously wonder how your code got so complex in the first place and strongly consider breaking it up into finer components for clarity! – Troyseph Oct 20 '15 at 13:56
  • 4
    If you need to use goto to escape your nested loop, you're using your nested loop wrong. It's literally that simple. The inner one should then almost always be in a returning function, the return value of which is used to break the outer. Repeat if necessary. – Jon Story Oct 22 '15 at 11:31
  • 7
    *If you are actually considering making goto a standard part of your logic, something has flown off the tracks.*: not true. – René Nyffenegger May 16 '16 at 11:01
  • 8
    Triple loop with obscure bools for quit AND more obscure ending conditions?? No, thanks. `goto Break` in this case. – Петър Петров Jan 25 '17 at 14:29
22

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.

mmdemirbas
  • 9,060
  • 5
  • 45
  • 53
Brian
  • 25,523
  • 18
  • 82
  • 173
20

Your code is extremely non-idiomatic and you should never write it. You're basically emulating C in C++ there. But others have remarked on that, and pointed to RAII as the alternative.

However, your code won't work as you expect, because this:

p = new int;
if(p==NULL) { … }

won't ever evaluate to true (except if you've overloaded operator new in a weird way). If operator new is unable to allocate enough memory, it throws an exception, it never, ever returns 0, at least not with this set of parameters; there's a special placement-new overload that takes an instance of type std::nothrow and that indeed returns 0 instead of throwing an exception. But this version is rarely used in normal code. Some low-level codes or embedded device applications could benefit from it in contexts where dealing with exceptions is too expensive.

Something similar is true for your delete block, as Harald as said: if (p) is unnecessary in front of delete p.

Additionally, I'm not sure if your example was chose intentionally because this code can be rewritten as follows:

bool foo() // prefer native types to BOOL, if possible
{
    bool ret = false;
    int i;
    // Lots of code.
    return ret;
}
Konrad Rudolph
  • 530,221
  • 131
  • 937
  • 1,214
  • New operator will return NULL. Checkout the link: http://msdn.microsoft.com/en-us/library/kftdy56f(VS.71).aspx – anand Dec 18 '08 at 21:03
  • 1
    No, it *won't*. That article uses a different `new` overload, namely nothrow operator new. This is what I referred to in my above answer. I'll try to clarify that further. – Konrad Rudolph Dec 18 '08 at 21:10
  • actually, the code emulates Fortran, rather than C. There is no reason for using GOTO in C eiter. – andreas buykx Dec 22 '08 at 20:30
  • @andreas: Admittedly, I'm not a C programmer. How do you handle errors and complex cleanup logic in C without resorting to `goto` or convoluted, nested `if` blocks? – Konrad Rudolph Dec 22 '08 at 23:55
  • ...or if you've overloaded operator== in a weird way. – Ferruccio Jul 10 '12 at 12:25
  • 1
    @Ferruccio You can’t overload operators for built-in types (`operator new` being an exception because it’s a function, despite its name, unlike the other operators). – Konrad Rudolph Jul 10 '12 at 12:27
  • @KonradRudolph - true, but `p` could be a user-defined type which is implicitly convertible from `int*`. – Ferruccio Jul 10 '12 at 12:34
  • @Ferruccio It’s declared as `int*` in OP’s code though … and that was the code I was referring to. – Konrad Rudolph Jul 10 '12 at 12:41
17

Probably not a good idea.

Marc Charbonneau
  • 40,399
  • 3
  • 75
  • 82
10

In general, and on the surface, there isn't any thing wrong with your approach, provided that you only have one label, and that the gotos always go forward. For example, this code:

int foo()
{
    int *pWhatEver = ...;
    if (something(pWhatEver))
    { 
        delete pWhatEver;
        return 1;
    }
    else
    {
        delete pWhatEver;
        return 5;
    }
}

And this code:

int foo()
{
    int ret;
    int *pWhatEver = ...;
    if (something(pWhatEver))
    { 
        ret = 1;
        goto exit;
    }
    else
    {
        ret = 5;
        goto exit;
    }
exit:
    delete pWhatEver;
    return ret;
}

really aren't all that different from each other. If you can accept one, you should be able to accept the other.

However, in many cases the RAII (resource acquisition is initialization) pattern can make the code much cleaner and more maintainable. For example, this code:

int foo()
{
    Auto<int> pWhatEver = ...;
    
    if (something(pWhatEver))
    {
        return 1;
    }
    else
    {
        return 5;
    }
}

is shorter, easier to read, and easier to maintain than both of the previous examples.

So, I would recommend using the RAII approach if you can.

Blanket Fox
  • 377
  • 4
  • 15
Scott Wisniewski
  • 24,561
  • 8
  • 60
  • 89
8

I think other answers (and their comments) have covered all the important points, but here's one thing that hasn't been done properly yet:

What your code should look like instead:

bool foo() //lowercase bool is a built-in C++ type. Use it if you're writing C++.
{
  try {
    std::unique_ptr<int> p(new int);
    // lots of code, and just return true or false directly when you're done
  }
  catch (std::bad_alloc){ // new throws an exception on OOM, it doesn't return NULL
    cout<<" OOM \n";
    return false;
  }
}

Well, it's shorter, and as far as I can see, more correct (handles the OOM case properly), and most importantly, I didn't need to write any cleanup code or do anything special to "make sure my return value is initialized".

One problem with your code I only really noticed when I wrote this, is "what the hell is bRetVal's value at this point?". I don't know because, it was declared waaaaay above, and it was last assigned to when? At some point above this. I have to read through the entire function to make sure I understand what's going to be returned.

And how do I convince myself that the memory gets freed?

How do I know that we never forget to jump to the cleanup label? I have to work backwards from the cleanup label, finding every goto that points to it, and more importantly, find the ones that aren't there. I need to trace through all paths of the function just to be sure that the function gets cleaned up properly. That reads like spaghetti code to me.

Very fragile code, because every time a resource has to be cleaned up you have to remember to duplicate your cleanup code. Why not write it once, in the type that needs to be cleaned up? And then rely on it being executed automatically, every time we need it?

einpoklum
  • 118,144
  • 57
  • 340
  • 684
jalf
  • 243,077
  • 51
  • 345
  • 550
8

Your example is not exception safe.

If you are using goto to clean up the code then, if an exception happens before the cleanup code, it is completely missed. If you claim that you do not use exceptions then you are mistaken because the new will throw bad_alloc when it does not have enough memory.

Also at this point (when bad_alloc is thrown), your stack will be unwound, missing all the cleanup code in every function on the way up the call stack thus not cleaning up your code.

You need to look to do some research into smart pointers. In the situation above you could just use a std::auto_ptr<>.

Also note in C++ code there is no need to check if a pointer is NULL (usually because you never have RAW pointers), but because new will not return NULL (it throws).

Also in C++ unlike (C) it is common to see early returns in the code. This is because RAII will do the cleanup automatically, while in C code you need to make sure that you add special cleanup code at the end of the function (a bit like your code).

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Martin York
  • 257,169
  • 86
  • 333
  • 562
  • Disagree on the need to check if a pointer is NULL. Sometimes you do need to check if you are not sure where or when a pointer will be initialized. – Mark Walsh May 15 '18 at 14:37
  • @MarkWalsh The point here is that `new` never returns `nullptr`. So no need to check the result of a `new` operation to see if it actually returned a pointer. If you get to the check then it will never be `nullptr`. – Martin York May 15 '18 at 17:28
6

As used in the Linux kernel, goto's used for cleanup work well when a single function must perform 2 or more steps that may need to be undone. Steps need not be memory allocation. It might be a configuration change to a piece of code or in a register of an I/O chipset. Goto's should only be needed in a small number of cases, but often when used correctly, they may be the best solution. They are not evil. They are a tool.

Instead of...

do_step1;
if (failed)
{
  undo_step1;
  return failure;
}

do_step2;
if (failed)
{
  undo_step2;
  undo_step1;
  return failure;
}

do_step3;
if (failed)
{
  undo_step3;
  undo_step2;
  undo_step1;
  return failure;
}

return success;

you can do the same with goto statements like this:

do_step1;
if (failed) goto unwind_step1;

do_step2;
if (failed) goto unwind_step2;

do_step3;
if (failed) goto unwind_step3;

return success;

unwind_step3:
  undo_step3;

unwind_step2:
  undo_step2;

unwind_step1:
  undo_step1;

return failure;

It should be clear that given these two examples, one is preferable to the other. As to the RAII crowd... There is nothing wrong with that approach as long as they can guarantee that the unwinding will always occur in exactly reverse order: 3, 2, 1. And lastly, some people do not use exceptions in their code and instruct the compilers to disable them. Thus not all code must be exception safe.

Harvey
  • 5,703
  • 1
  • 32
  • 41
  • Not sure why this answer was down voted. I'm guessing an anti-goto zealot? – Harvey Apr 14 '09 at 22:13
  • 2
    Maybe because your code is pure C code, while the question was tagged `C++`? In C++, cleanup code should be done in dtors of local automatic objects. – sbi Oct 30 '09 at 23:15
  • eh, that's fair. I'm used to a lot of embedded environments where C++ is often used just as a thin wrapper around C code. – Harvey Feb 15 '10 at 22:49
  • And in Embedded, even a function call with its Stack Unwinding will be more operations than a goto / asm jump instruction to cleanup routine. Oh, and, forced inline, of course. – Петър Петров Jan 25 '17 at 14:34
  • @ПетърПетров And any decent compiler would optimize the RAII in jumps. So there will be no performance difference. – dvr33 Feb 16 '20 at 17:24
6

In the eight years I've been programming I've used goto a lot, most of that was in the first year when I was using a version of GW-BASIC and a book from 1980 that didn't make it clear goto should only be used in certain cases. The only time I've used goto in C++ is when I had code like the following, and I'm not sure if there was a better way.

for (int i=0; i<10; i++) {
    for (int j=0; j<10; j++)
    {
        if (somecondition==true)
        {
            goto finish;
        }
        //Some code
    }
    //Some code
}
finish:

The only situation I know of where goto is still used heavily is mainframe assembly language, and the programmers I know make sure to document where code is jumping and why.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Jared
  • 39,513
  • 29
  • 110
  • 145
5

In general, you should design your programs to limit the need for gotos. Use OO techniques for "cleanup" of your return values. There are ways to do this that don't require the use of gotos or complicating the code. There are cases where gotos are very useful (for example, deeply nested scopes), but if possible should be avoided.

Marcin
  • 12,245
  • 9
  • 42
  • 49
  • 2
    Deeply nested scopes can be refactored out into a separate function, and then a single return statement easily replaces your goto there as well. :) – jalf Dec 18 '08 at 21:43
5

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

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
too much php
  • 88,666
  • 34
  • 128
  • 138
  • But then, Linus' opinions are often quite whacky in themselves. After all, he (co-)invented the flame war. – Konrad Rudolph Dec 19 '08 at 08:32
  • Also, C is a bit different than C++. I can see goto being good, in moderation, if used extremely carefully, in some rare circumstances, if you're writing straight C, but if you have the tools of C++ at your disposal, you shouldn't be writing with C idioms. – Adam Jaskiewicz Dec 19 '08 at 15:38
  • While Linus is a certifiable nut, he's not wrong about goto statements. When used correctly (as with all things), they are perfectly fine and sometimes preferable to the alternative. – Harvey Dec 22 '08 at 18:48
5

The downside of GOTO is pretty well discussed. I would just add that 1) sometimes you have to use them and should know how to minimize the problems, and 2) some accepted programming techniques are GOTO-in-disguise, so be careful.

1) When you have to use GOTO, such as in ASM or in .bat files, think like a compiler. If you want to code

 if (some_test){
  ... the body ...
}

do what a compiler does. Generate a label whose purpose is to skip over the body, not to do whatever follows. i.e.

 if (not some_test) GOTO label_at_end_of_body
  ... the body ...
label_at_end_of_body:

Not

 if (not some_test) GOTO the_label_named_for_whatever_gets_done_next
  ... the body ...

the_label_named_for_whatever_gets_done_next:

In otherwords, the purpose of the label is not to do something, but to skip over something.

2) What I call GOTO-in-disguise is anything that could be turned into GOTO+LABELS code by just defining a couple macros. An example is the technique of implementing finite-state-automata by having a state variable, and a while-switch statement.

 while (not_done){
    switch(state){
        case S1:
            ... do stuff 1 ...
            state = S2;
            break;
        case S2:
            ... do stuff 2 ...
            state = S1;
            break;
        .........
    }
}

can turn into:

 while (not_done){
    switch(state){
        LABEL(S1):
            ... do stuff 1 ...
            GOTO(S2);
        LABEL(S2):
            ... do stuff 2 ...
            GOTO(S1);
        .........
    }
}

just by defining a couple macros. Just about any FSA can be turned into structured goto-less code. I prefer to stay away from GOTO-in-disguise code because it can get into the same spaghetti-code issues as undisguised gotos.

Added: Just to reassure: I think one mark of a good programmer is recognizing when the common rules don't apply.

Mike Dunlavey
  • 40,059
  • 14
  • 91
  • 135
4

Using goto to go to a cleanup section is going to cause a lot of problems.

First, cleanup sections are prone to problems. They have low cohesion (no real role that can be described in terms of what the program is trying to do ), high coupling (correctness depends very heavily on other sections of code), and are not at all exception-safe. See if you can use destructors for cleanup. For example, if int *p is changed to auto_ptr<int> p, what p points to will be automatically released.

Second, as you point out, it's going to force you to declare variables long before use, which will make it harder to understand the code.

Third, while you're proposing a fairly disciplined use of goto, there's going to be the temptation to use them in a looser manner, and then the code will become difficult to understand.

There are very few situations where a goto is appropriate. Most of the time, when you are tempted to use them, it's a signal that you're doing things wrong.

David Thornley
  • 56,304
  • 9
  • 91
  • 158
  • okay what about when we want to avoid multiple return paths from routing and also want to return some error value. Goto easily avoid multiple return paths and we can set error value in goto section . That way we never miss setting return error value. – anand Dec 18 '08 at 20:51
  • You think multiple return paths are a problem, and gotos are not? – David Thornley Dec 18 '08 at 21:23
  • 2
    Why do you consider multiple return paths a problem? And if you don't declare the return value ahead of time, you never forget setting it either. (instead of bRetVal = FALSE at the top of the function, just return true/false directly. – jalf Dec 18 '08 at 22:10
4

The entire purpose of the every-function-has-a-single-exit-point idiom in C was to put all the cleanup stuff in a single place. If you use C++ destructors to handle cleanup, that's no longer necessary -- cleanup will be done regardless of how many exit points a function has. So in properly-designed C++ code, there's no longer any need for this kind of thing.

Head Geek
  • 38,128
  • 22
  • 77
  • 87
3

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.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Петър Петров
  • 1,966
  • 1
  • 17
  • 14
3

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

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
mstrobl
  • 2,381
  • 14
  • 16
  • 4
    Please also read "Structured Programming with goto Statements" by Donald Knuth, http://pplab.snu.ac.kr/courses/adv_pl05/papers/p261-knuth.pdf. Using goto for error handling is a perfectly valid strategy in C, and usually is the best approach. It is used heavily in the linux kernel. Now for C++ on the other hand there might very well be other better approaches, which makes goto not a good choice, my C++ knowledge is too weak to say anything on that. – hlovdal May 11 '09 at 18:06
3

Goto provides better don't repeat yourself (DRY) when "tail-end-logic" is common to some-but-not-all-cases. Especially within a "switch" statement I often use goto's when some of the switch-branches have tail-end-commonality.

switch(){
   case a:  ... goto L_abTail;
   case b: ... goto L_abTail;
L_abTail: <commmon stuff>
    break://end of case b
case c:
.....
}//switch

You have probably noticed than introducing additional curly-braces is enough to satisfy the compiler when you need such tail-end-merging in-the-middle of a routine. In other words, you don't need to declare everything way up at the top; that's inferior readability indeed.

...
   goto L_skipMiddle;
{
    int declInMiddleVar = 0;
    ....
}
L_skipMiddle: ;

With the later versions of Visual Studio detecting the use of uninitialized variables, I find myself always initializing most variables even though I think they may be assigned in all branches - it's easy to code a "tracing" statement which refs a variable that was never assigned because your mind doesn't think of the tracing statement as "real code", but of course Visual Studio will still detect an error.

Besides don't repeat yourself, assigning label-names to such tail-end-logic even seems to help my mind keep things straight by choosing nice label names. Without a meaningful label your comments might end up saying the same thing.

Of course, if you are actually allocating resources then if auto-ptr doesn't fit, you really must use a try-catch, but tail-end-merge-don't-repeat-yourself happens quite often when exception-safety is not an issue.

In summary, while goto can be used to code spaghetti-like structures, in the case of a tail-end-sequence which is common to some-but-not-all-cases then the goto IMPROVES the readability of the code and even maintainability if you would otherwise be copy/pasting stuff so that much later on someone might update one-and-not-the-other. So it's another case where being fanatic about a dogma can be counterproductive.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
pngaz
  • 377
  • 2
  • 10
2

A lot of people freak out with gotos are evil; they are not. That said, you will never need one; there is just about always a better way.

When I find myself "needing" a goto to do this type of thing, I almost always find that my code is too complex and can be easily broken up into a few method calls that are easier to read and deal with. Your calling code can do something like:

// Setup
if(
     methodA() &&
     methodB() &&
     methodC()
 )
 // Cleanup

Not that this is perfect, but it's much easier to follow since all your methods will be named to clearly indicate what the problem might be.

Reading through the comments, however, should indicate that your team has more pressing issues than goto handling.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Bill K
  • 62,186
  • 18
  • 105
  • 157
  • It's a bad programming habbit, there is no need to use them as this will only get you to write longer methods. You can replace the goto in his example by: if (p) delete p; Why add more lines to reach the same? – Tamara Wijsman Dec 19 '08 at 01:35
  • just what I said, thanks for the reinforcement. – Bill K Dec 19 '08 at 21:34
1

All of the above is valid, you might also want to look at whether you might be able to reduce the complexity of your code and alleviate the need for goto's by reducing the amout of code that is in the section marked as "lot of code" in your example. Additionaly delete 0 is a valid C++ statement

Harald Scheirich
  • 9,676
  • 29
  • 53
1

Using GOTO labels in C++ is a bad way to program, you can reduce the need by doing OO programming (deconstructors!) and trying to keep procedures as small as possible.

Your example looks a bit weird, there is no need to delete a NULL pointer. And nowadays an exception is thrown when a pointer can't get allocated.

Your procedure could just be wrote like:

bool foo()
{
    bool bRetVal = false;
    int p = 0;

    // Calls to various methods that do algorithms on the p integer
    // and give a return value back to this procedure.

    return bRetVal;
}

You should place a try catch block in the main program handling out of memory problems that informs the user about the lack of memory, which is very rare... (Doesn't the OS itself inform about this too?)

Also note that there is not always the need to use a pointer, they are only useful for dynamic things. (Creating one thing inside a method not depending on input from anywhere isn't really dynamic)

Tamara Wijsman
  • 12,198
  • 8
  • 53
  • 82
  • Make p an auto_ptr or shared_ptr, and you don't have to worry about whether the delete p; is ever executed. – David Thornley Dec 18 '08 at 21:09
  • Rewritten the answer, and besides that I'm not a boost user (yet) as we need to use the delete method at university. Code profilers can assist you when you forget to use delete somewhere in the code. – Tamara Wijsman Dec 18 '08 at 21:14
  • Bad univerity, then. auto_ptr is in the standard library, and boost's shared_ptr will be in next year. Universities should not teach you to use delete, that's a technique from 10+ years ago. (It's OK to show delete when explaining how RAII works, of course) – MSalters Dec 19 '08 at 12:02
1

I am not going to say that goto is always bad, but your use of it most certainly is. That kind of "cleanup sections" was pretty common in early 1990's, but using it for new code is pure evil.

Nemanja Trifunovic
  • 24,346
  • 3
  • 50
  • 88
  • I would stay away from words like "pure evil". I would reserve that for things like genocide. We're only programming, after all. – Mike Dunlavey Dec 22 '08 at 20:48
  • "Pure evil" is among the most common phrases you can hear in any programming discussion. Other ones are "heresy", "blasphemy", "sin"... – Nemanja Trifunovic Dec 25 '08 at 02:04
1

The easiest way to avoid what you are doing here is to put all of this cleanup into some kind of simple structure and create an instance of it. For example instead of:

void MyClass::myFunction()
{
   A* a = new A;
   B* b = new B;
   C* c = new C;
   StartSomeBackgroundTask();
   MaybeBeginAnUndoBlockToo();

   if ( ... )
   {
     goto Exit;
   }

   if ( ... ) { .. }
   else
   {
      ... // what happens if this throws an exception??? too bad...
      goto Exit;
   }

Exit:
  delete a;
  delete b;
  delete c;
  StopMyBackgroundTask();
  EndMyUndoBlock();
}

you should rather do this cleanup in some way like:

struct MyFunctionResourceGuard
{
  MyFunctionResourceGuard( MyClass& owner ) 
  : m_owner( owner )
  , _a( new A )
  , _b( new B )
  , _c( new C )
  {
      m_owner.StartSomeBackgroundTask();
      m_owner.MaybeBeginAnUndoBlockToo();
  }

  ~MyFunctionResourceGuard()
  {
     m_owner.StopMyBackgroundTask();
     m_owner.EndMyUndoBlock();
  }

  std::auto_ptr<A> _a;
  std::auto_ptr<B> _b;
  std::auto_ptr<C> _c;

};

void MyClass::myFunction()
{
   MyFunctionResourceGuard guard( *this );

   if ( ... )
   {
     return;
   }

   if ( ... ) { .. }
   else
   {
      ...
   }
}
Michel
  • 1,456
  • 11
  • 16
1

A few years ago I came up with a pseudo-idiom that avoids goto, and is vaguely similar to doing exception handling in C. It has been probably already invented by someone else so I guess I "discovered it independently" :)

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

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

       // Lot of code...

       bRetVal = TRUE;

    } while (false);

   if(p)
   {
     delete p;
     p= NULL;
   }

   return bRetVal;
}
ggambetta
  • 3,312
  • 6
  • 32
  • 42
1

The code you're giving us is (almost) C code written inside a C++ file. The kind of memory cleaning you're using would be OK in a C program not using C++ code/libraries.

In C++, your code is simply unsafe and unreliable. In C++ the kind of management you're asking for is done differently. Use constructors/destructors. Use smart pointers. Use the stack. In a word, use RAII.

Your code could (i.e., in C++, SHOULD) be written as:

BOOL foo()
{
   BOOL bRetVal = FALSE;

   std::auto_ptr<int> p = new int;

   // Lot of code...

   return bRetVal ;
}

(Note that new-ing an int is somewhat silly in real code, but you can replace int by any kind of object, and then, it makes more sense). Let's imagine we have an object of type T (T could be an int, some C++ class, etc.). Then the code becomes:

BOOL foo()
{
   BOOL bRetVal = FALSE;

   std::auto_ptr<T> p = new T;

   // Lot of code...

   return bRetVal ;
}

Or even better, using the stack:

BOOL foo()
{
   BOOL bRetVal = FALSE;

   T p ;

   // Lot of code...

   return bRetVal;
}

Anyway, any of the above examples are magnitudes more easy to read and secure than your example.

RAII has many facets (i.e. using smart pointers, the stack, using vectors instead of variable length arrays, etc.), but all in all is about writing as little code as possible, letting the compiler clean up the stuff at the right moment.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
paercebal
  • 81,378
  • 38
  • 130
  • 159
0

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:;
}
Hazok
  • 5,373
  • 4
  • 38
  • 48
0

Try it this way:

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

   p = new int;
   if (p == NULL)
   {
     cout<<" OOM \n";
   }
   else
   {
       // Lot of code...
   }

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

In the section "Lot of code", "Lot of code" is a good indication that you probably should refactor this section into one or more methods or functions.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Matthew
  • 2,062
  • 13
  • 11
  • 1
    This suffers from the same problems that have already been pointed out. Don't write code like that in C++. Not even low-level code. – Konrad Rudolph Dec 18 '08 at 21:00
  • @Konrad: I understand you take issue with the various tests on p, but I think that's a side issue. Matthew's suggestion is AFAIK the classic "correct" method for avoiding GOTO -- use real branching logic instead. – Dave Costa Dec 18 '08 at 21:04
  • I disagree @Konrad. It may not be out of the book, it may miss that delete NULL is valid, but OTOH the posters were wrong about exceptions on an OOM error (hint: set_new_handler()). And in no way is this post -1, this is ridiculous, so I will upvote. And the refactoring remark is very true aswell. – mstrobl Dec 18 '08 at 21:09
  • 2
    Konrad is right, this misses a fundamental point. Screw the tests on p, they're not important. What matters is that you're using simple, error-prone branching when C++ gives you much better tools for handling cleanup, such as RAII. – jalf Dec 18 '08 at 21:44
  • @mstrobl: The null test here was only a tiny part of my criticism. The whole code, as it stands, is an antipattern in C++. jalf understood me. Also, the “refactor” remark might be valid but I find it overrated. Some functions *do* get long in practice and there's nothing you can do to prevent it. – Konrad Rudolph Dec 18 '08 at 22:26
  • 1
    There's nothing you can do to *prevent* it, but you can *usually* fix it, too. In any case, it's something to seriously look at doing, before you start throwing in GOTOs and cleanup code. – Adam Jaskiewicz Dec 19 '08 at 02:51
  • 1
    As far as I see it, Mattew's solution is a good C solution (remplace new/delete by malloc/free). But this is a BAD C++ solution: No RAII (either stack or smart pointer), ignorance the fact a failing new is supposed to throw, etc.. Re-reading the question I see both use of "new" and tag "c++"... – paercebal Dec 20 '08 at 16:38
0

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.

Filip Ekberg
  • 36,033
  • 20
  • 126
  • 183
0

The previous comments are all good reasons not to use goto.

I can speak from experience that for other programmers who might need to maintain your code goto's make following the logic very hard. I came into a situation of heavy goto spaghetti code and with my OO background it was a nightmare to debug and make changes. Yes, this code used goto's for cleanup functions as well. Very frustrating when not needed. Do not use goto's unless absolutely necessary.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
0

I may have missed something: you jump to the label Exit if P is null, then test to see if it's not null (which it's not) to see if you need to delete it (which isn't necessary because it was never allocated in the first place).

The if/goto won't, and doesn't need to delete p. Replacing the goto with a return false would have the same effect (and then you could remove the Exit label).

The only places I know where goto's are useful are buried deep in nasty parsers (or lexical analyzers), and in faking out state machines (buried in a mass of CPP macros). In those two cases they've been used to make very twisted logic simpler, but that is very rare.

Functions (A calls A'), Try/Catches and setjmp/longjmps are all nicer ways of avoiding a difficult syntax problem.

Paul.

Paul W Homer
  • 2,728
  • 1
  • 19
  • 25
0

Ignoring the fact that new will never return NULL, take your code:

  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;
  }

and write it like this:

  BOOL foo()
  {
     BOOL bRetVal = FALSE;

     int *p = new int;

     if (p!=NULL)
     {
        // Lot of code...

        delete p;
     }
     else
     {
        cout<<" OOM \n";
     }

     return bRetVal;
  }
jussij
  • 10,370
  • 1
  • 33
  • 49
0

That code has a bunch of problems, most of which were pointed out already, for example:

  • The function is too long; refactoring out some code into separate functions might help.

  • Using pointers when normal instances will probably work just fine.

  • Not taking advantage of STL types such as auto_ptr

  • Incorrectly checking for errors, and not catching exceptions. (I would argue that checking for OOM is pointless on the vast majority of platforms, since if you run out of memory you have bigger problems than your software can fix, unless you are writing the OS itself)

I have never needed a goto, and I've always found that using goto is a symptom of a bigger set of problems. Your case appears to be no exception.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
metao
  • 2,784
  • 1
  • 18
  • 15
0

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

In other words, you want to separate the program logic from simple repetitive tedious routines, like freeing a resource which might be reserved in different locations of code.

The exception handling technique is an error handling logic which works in parallel with program logic. It's a more elegant solution since it provides such separation while offering the ability to move control to other blocks of code exactly as the goto statement does, so I modified your script to look like this:

class auxNullPtrException : public std::exception {
    public:
        auxNullPtrException::auxNullPtrException()
            : std::exception( " OOM \n") {}
    };

    BOOL foo()
    {
        BOOL bRetVal = FALSE;
        try {
            int *p = NULL;
            p = new int;
            if (p == NULL)
            {
                throw auxNullPtrException();
            }
            // Lot of code...
         }
         catch(auxNullPtrException & _auxNullPtrException)
         {
             std::cerr<<_auxNullPtrException.what();
             if(p)
             {
                 delete p;
                 p = NULL;
             }
         }
         return bRetVal;
    }
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Josef
  • 353
  • 1
  • 2
  • 8
-1

From all the previous comments:

  1. goto is very very bad
  2. It makes code hard to read and understand.
  3. It can cause the well-known issue "spaghetti code"
  4. Everyone agree that it should not be done.

But I am using in following scenario

  1. It's used to go forward and only to one label.
  2. goto section is used to cleanup code and set a return value. If I don't use goto then I need to create a class of every data type. Like I need to wrap int * into a class.
  3. It's being followed in the whole project.

I agree that it's bad, but still it's making things much easier if followed properly.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
anand
  • 11,071
  • 28
  • 101
  • 159
  • the int* already exists. It's called std::auto_ptr or boost::shared_ptr. But what you're saying is "it doesn't matter because the entire project already uses gotos", so... why did you ask in the first place? Once again, pick a language. C uses goto, C++ doesn't. – jalf Dec 18 '08 at 21:48
  • std::auto_ptr<> is your friend. It is also Exception safe. None of your code is. – Martin York Dec 18 '08 at 22:00
  • Easier often does not equate to correct, unfortunately. – Gene Roberts Dec 18 '08 at 22:24
  • Going forward means you can bypass the initialization for some symbol. Assuming the compiler lets you do this, something with a constructor would be in an undefined state. My guess is that the only good way to use goto is to exit scopes. You're coding C++, so just do it. Use RAII. – paercebal Dec 20 '08 at 17:00
-4

I don't know where this thing about goto come from...

In a compiled language each and every conditional instructions (if, switch, for, while, etc.) resolve in "cmp" "jmp" or "j??" in machine code (jmp IS goto).

In fact, a really well optimised code is aware of best execution paths and MUST therefore use "goto"... It's even better to do a linear piece of code with gotos than methods and calls when the stack is not used ("call" = "push"+"jmp").

There's absolutely no good reason why you shouldn't use GOTO in C++: generated code is full of "jmp"s everywhere anyway.

It's only a problem in scripts (where it is often not available), because the destination of goto has not necessarily been interpreted when goto instruction is.

The initial argument against goto is that the code is harder to check.

That's absurd: Code is not made to be checked (or only ONCE): It's made to be executed, to be small and fast. An optimized piece of code must avoid redundancy (by reusing the same instructions) and avoid runtime checks (exceptions that are not related to hardware malfunctions should all be avoided at design time, NOT at runtime).

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
  • 1
    Modern code is made to be readable, predictable and maintainable. Goto is often (but not always) a sign that this code is not. But it is silly to assert it "is not made to be checked." Most software development these days does involve code reviews. – Phil Hord Sep 21 '12 at 22:27
  • .. And sometimes, complicated algorithms, described in comments with steps will be FAR more readable with goto stepX – Петър Петров Apr 22 '13 at 00:54
  • 1
    Beware premature optimisation, let the compiler add the `goto`s, make the code maintainable, optimise when absolutely proven there is a need! – Troyseph Oct 20 '15 at 14:02