one question about goto's

Pages: 12
question ::
if goto should never be needed and should never be used, why is it there then?
Last edited on
It's not universally agreed that goto should never be used. But even if it was, it is very difficult to remove anything from C++. There are millions of lines of code that use goto, they are live in production across the world. If the compilers suddenly start rejecting that code, people simply won't use the new compilers.

You think goto is useless, how about the operator++ for bools? It's been obsolete since 1998, but it can't be removed because there are codebases out there that rely on it.

goto does actually have its uses. Even if no live code was using it, it still should not be removed. It's just that beginners have no idea of how to use it and don't realize a program jumping around the code like a madman is extremely poor design.
well, i'm a beginner, and i got a lot of advices to not to "goto" in my programs which i got reviewed by experts and many time me too feel that using goto creates some fuss in the operation of many of my programs and sometimes gives hilarious errors.. @_@...
That advice you were given is good advice. Don't use goto, unless you absolutely have to, and you're absolutely sure you're expert enough in C++ to understand all the dangers and implications of using it.

And even then, think twice about it.
hmm...
@MikeyBoy
can you please tell me some dangers of using it?
Leads to what is called spaghetti code. If you overuse goto it will be jumping all over your code which makes it harder to read. That is the biggest issue with it that I know of.
calling functions and using of global variables, classes, structures also makes program jumping whole over the program then why only goto is a problem?
Code in C++ is very structured.

Everything is arranged in clear {blocks} where nested braces and indentation levels show a clear flow of logic. You can expect that one line of code will lead to the next.

Except in infrequent cases where the code will take an "early out" to escape one or more blocks (as is the case of a return, continue, or break statement). And even then... the "early out" is just an escape, and is still linear and predictable.


Goto, on the other hand takes that structure and throws it out the window. If you're reading code that has a jump-to label... you have to be weary that any point of the function might jump back to it. Or maybe multiple points in the function might jump back to it. There's no longer any way to know what code has run before the label unless you read the entire function.



So yeah. It can make code much harder to follow and understand.


I agree with what's been said. goto should be used very sparingly. And newbies should avoid using it altogether -- until they are able to recognize why it's dangerous and when it's appropriate to use it (read: it rarely is).
yes. i also agree with the unpredictable nature of goto.
aalok wrote:
calling functions and using of global variables, classes, structures also makes program jumping whole over the program then why only goto is a problem?

Well some frown on the use of global variables that aren't constants. I use constant globals a lot (ie. const int SCREEN_W = 640;). As for functions, classes, and structures that kind of jumping is more 'structured' for lack of a better word. Classes are for creating objects and are self contained, structures are the same idea while functions when their names are encountered the code enters the function's definition until it gets to the end of the function and then goes to the next line after the function call.

I may not be explaining that very well though. I think Disch explained it better than me actually.
goto is not bad it is just misused. Learn what it does and how to use it. There is often a better way than using goto but sometimes you will find that it is a simple way to achieve something.

my advice:
Don't use goto until you have learnt enough to know why using goto is 'bad', then you will have learnt enough to use goto properly.

__________________________________
PS: It is not worth asking for an example of a good time to use goto as such an example would be non-trivial and any trivial example would be met with a counter "do it without goto like this"
Last edited on by Canis lupus
Also... using goto is very dangerous:

http://xkcd.com/292/
I thought this came up before and it was sort of agreed that a UDP client receiving a broadcast or stream was a non-trivial example of when a C++ application might use goto? Like if a packet fails the checksum or the 'Length' is equal to the size of the header (heartbeat packet) or whatever else might go wrong, then it just gets dropped. It doesn't get stored in the receiving devices buffer or forwarded to the next function or whatever else might happen with good packets. I really want to say I read that here because I remember in the example code someone had they were re-declaring a variable at every iteration of the control loop and when I said something about it, they pointed out that jumping to a label before a variables declaration calls it's destructor and I didn't know that before. Maybe that was just all in my head though...
computergeek01 wrote:
they pointed out that jumping to a label before a variables declaration calls it's destructor and I didn't know that before. Maybe that was just all in my head though...


This is another hazard of goto. It confuses/breaks variable scope rules. Normally variables have a clear scope: they are constructed when you declare them, they are destroyed when they go out of scope. But with goto you can jump in and out of a variable's scope leading to confusing ctor/dtor calls.

I thought this came up before and it was sort of agreed that a UDP client receiving a broadcast or stream was a non-trivial example of when a C++ application might use goto?


There are definitely non-trivial examples. The problem is showing an example in a thread is difficult because to fit it in a thread it has to be trivial.



Really the only reasonable arguments I can remember hearing for goto are:
1) breaking out of multiple layers of nested loops
2) Having error checking code jump to common cleanup code.

#1 can usually (but not always) be avoided through more organized/cleaner code.
#2 can usually (always?) be avoided with RAII and/or exceptions.



Regardless... FWIW... in the languages I use that don't have goto available... I find myself never missing it.
One thing you have to also be careful about showing trivial and non-trivial examples for using something is that some beginners mentally link those examples to that feature and will immediately use it every time it comes up in code. I admit it is rare, but it happens.

[EDIT]Actually, thinking back to some of the beginner threads I've seen elsewhere, it isn't so rare.
Last edited on
1
2
3
4
#if __cplusplus >= 201103L
#define goto static_assert(false, "This language feature has been deprecated in C++11.  \
If you REALLY need this feature, try inlining assembly.  Good Luck.");
#endif 


Problem solved.

Certainly this can be also be said about switches (which can be equally as evil as gotos)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
int count = ?;
{
    int n = (count + 7) / 8;
    switch (count % 8)
    {
    case 0:
             do {
                 *to = *from++;
    case 7:      *to = *from++;
    case 6:      *to = *from++;
    case 5:      *to = *from++;
    case 4:      *to = *from++;
    case 3:      *to = *from++;
    case 2:      *to = *from++;
    case 1:      *to = *from++;
           } while (--n > 0);
    }
}


...but instead of shunning the sinner, could we devise a use-case where it would be desirable to use?
Last edited on
Duff's Device is useful if your compiler is stupid and doesn't know what the word "optimization" means, let alone what loop unrolling is.
@Luc Lieber
That solution is only viable if the beginner actually uses it or if the person giving the example bothers to show it otherwise it is a lost fix.
> Normally variables have a clear scope: they are constructed when you declare them,
> they are destroyed when they go out of scope.

Normally Always variables have a clear scope: they are constructed when you declare define them, they are destroyed when they go out of scope (if they have an automatic storage duration).

Always. Presence of goto does not change the object lifetime and scoping rules of the language.


> This is another hazard of goto. It confuses/breaks variable scope rules.
> ...
> But with goto you can jump in and out of a variable's scope leading to confusing ctor/dtor calls.

It is not a hazard of goto. This is the hazard with programmers who are confused about scoping rules, about object lifetime and about initialization and deinitialization. They would remain confused programmers even if they decided never to use a goto. For instance, they would have the same problems when they use a switch-case construct - case and default are labels, with the switch being an implicit goto to the appropriate label.

Fortunately, compilers do not get confused about object lifetime, even when they encounter a goto or a switch-case. They detect silly scoping errors and won't pass the code.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#include <string>

void foo( int i )
{
    label:
        {
            int j = i ;

            i -= j ;
        }

        if( i > 10 ) goto label ; // fine
}

void bar( int i )
{
        {
            int j = i ;
    label:
            i -= j ;
        }

        if( i > 10 ) goto label ; // *** error: jump bypasses variable initialization
}

void baz( int i )
{
        {
            std::string a ;
    label:
            --i ;
        }

        if( i > 10 ) goto label ; // *** error: jump bypasses variable initialization
}

http://coliru.stacked-crooked.com/a/3b25ae271e9f785b

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#include <iostream>

struct A
{
    int v ;
    A( int i ) : v(i) { std::cout << v << " A::constructor\n" ; }
    ~A() { std::cout << v << " A::destructor\n" ; }
};

void foobar( int i )
{
        std::cout << "foobar(" << i << ")\n" ;
        {
            A a(1) ;
            if( i > 5 ) goto label ;
            A b(2) ;
            if( i > 0 ) goto label ;
            A c(3) ;
            --i ;
        }
    label:
        --i ;
        std::cout << "..................\n" ;
}

int main()
{
    foobar(22) ;
    foobar(2) ;
    foobar(-2) ;
}
http://coliru.stacked-crooked.com/a/470476e18d0410df










foobar(22)
1 A::constructor
1 A::destructor
..................
foobar(2)
1 A::constructor
2 A::constructor
2 A::destructor
1 A::destructor
..................
foobar(-2)
1 A::constructor
2 A::constructor
3 A::constructor
3 A::destructor
2 A::destructor
1 A::destructor
..................
Pages: 12