Jump to content

  • Log In with Google      Sign In   
  • Create Account


C++ - Is Goto a Good Practice?


Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

  • You cannot reply to this topic
46 replies to this topic

#21 armitroner   Members   -  Reputation: 132

Like
0Likes
Like

Posted 12 November 2012 - 08:34 AM


I only used goto in one small section, since I don't have much need for it elsewhere.

You are essentially abusing goto to create a loop. Instead, use an explicit loop:
...
Note that this automatically handles the case where the user types an invalid option by looping around, though it is generally nicer to print a specific message in this case.

Another potential improvement is to dynamically remove invalid options from the menu. Something like this:
...
I'm not sure if you are familiar with std::vector or function pointers. Feel free to ask a question if you don't understand what this code is doing.


From what I can see in the second example, it's working sort of like an array. It appears to be creating a single, erm, (for lack of a better term) method that carries the other functions in it, kinda like how a class works? Then it grabs how many functions are underneath CombatChoice and displays them, dependent upon wether or not they meet the conditions given when using the push_back function. (not sure what push_back is)
Finally, when choosing the option, the reason you created that variable when creating the menu was to add an extra bumper in case the player chose the number of an option that wasn't even there.

I'll do a bit of reading on std::vector, since this is the first time I've come across the term. This was actually my first serious C++ project, so I had to hunt down tons of stuff on the net. Posted Image
Anyhow, thanks for the advice, and I'll be working on improving my code once my compiler gets fixed... Posted Image

Sponsor:

#22 carangil   Members   -  Reputation: 490

Like
3Likes
Like

Posted 12 November 2012 - 04:01 PM

Goto still exists for a reason. At work, we have a large C codebase that has a few goto's in it. It's used as 'goto cleanup', to bail-out of a function, but allow for freeing objects. In C++ you would use an exception or just let the destructors do their job, in C there is no such luxury. You might also be able to make a case for using it in a C++ program if you need to manually free something that doesn't have a destructor ( maybe you were interfacing to something written in plain C), but you would probably want to wrap your C structs into a C++ object with a proper destructor instead.

I do see this sometimes, and I think this construct is worse than a goto:
[source lang="C++"] do { stuff; if (!stuff) break; //really just a 'goto' in disguise stuff; if (oh_crap) break; //another goto for (i=0;xxx;xxx) { if (whatever(i)) { outer_break=true; break; } } if (outer_break) break; // well wasn't that awkward stuff;} while (0);free(things);[/source]
As you can see above, break is really just as bad as goto, and if you need to break from inside an inner loop, it gets awkward.

The other acceptable use I see for goto are the gcc extenstion of 'computed gotos' where you can have label pointers, and build a jump table. This is handy if you are writing a bytecode interpreter, BUT is really just the same thing as the jump table that a good compiler is supposed to try to make for a switch/case statement.

Other than these two cases, goto is almost always a mistake.

#23 Amadeus H   Members   -  Reputation: 1180

Like
2Likes
Like

Posted 13 November 2012 - 07:32 AM

Obligatory XKCD.

Posted Image

#24 dmatter   Crossbones+   -  Reputation: 3030

Like
2Likes
Like

Posted 13 November 2012 - 05:52 PM

As far as I know there is no case where a goto in C++ is the best tool for the job. I have never had cause to use it in C++ and I would not be overly happy to read or maintain code that uses it either.

Goto has a couple of uses, chiefly amongst them is making loops and exiting out of nested code. Instead it's better to prefer explicit loops and factoring nested code into functions which can be exited using return.

I combination of these alternatives can be applied to your function, including some minor restructuring that makes it a little cleaner:


void Combat::combatChoice(Character& C) {

    if (C.health <= 0) {

        cout << "----------------- You died... ------------------" << endl;

        cout << "Oh dear, it seems you have died... Game Over." << endl;

        return;

    }

	

    for (;;) {

        cout << "----------------- Battle Options ------------------" << endl;

        C.Display();

        cout << "What do you want to do? \n"

             << "Type the number of the action and press enter. \n"

             << "[1] Melee Attack \n"

             << "[2] Gun Attack \n"

             << "[3] Health Potion" << endl;



        short choice;

        cin >> choice;

		

        cout << "\n----------------- Battle Results ------------------" << endl;

        switch (choice) {

            case 1:

                C.meleeAttack(M);

                return;



            case 2:

                if(C.ammo > 0) {

                    C.gunAttack(M);

                    return;

                }

				

                cout << "You're out of ammo! \n" << endl;

                break;



            case 3:

                if(C.potions > 0) {

                    C.useHP();

                    return;

                }

				

                cout << "You're out of potions! \n" << endl;

                break;

				

            default:

                cout << "Whoops you choose an incorrect battle option, try again!\n\n";

        }

    }

}


So we've used an infinite loop which is basically saying "keep going till the user provides us with a workable option" (and such a thing would make a good code comment above the loop). Once a valid option has succeeded it exits from the function entirely using mid-function returns.

I find mid-function/early returns are often easier and clearer than using control variables to guide execution out of loops toward the end of a function. There are cases to be made either way.

I think rip-off's second example is better factored, more extensible and offers a superior experience for the user. An observation off the back of it is that having battle actions as member functions on a Character is slightly awkward as it involves a second abstraction for unifying the interface to them: f(C, M)
It may make sense to separate the action concept out as a first-class citizen, e.g. MeleeAttack::apply(Character & C, Monster & M);
Then just register all your Attack actions into the menu vector. You could add other member functions, such as one that predicates whether the action is even valid on the current menu (otherwise the menu code has to know something about what each attack requires).

Edited by dmatter, 13 November 2012 - 05:57 PM.


#25 Vilem Otte   Crossbones+   -  Reputation: 1390

Like
0Likes
Like

Posted 13 November 2012 - 07:50 PM

I actually used goto once or twice in C to decrease number of nested loops in code (it made code look a bit better)... I could've used function there though, but I didn't want (separating that code would be a hell for anyone who would read it).

Basically if you are beginner (and assuming that, because this is in forums For Begginers), you shouldn't use it at all. Posted Image

My current blog on programming, linux and stuff - http://gameprogrammerdiary.blogspot.com


#26 Khatharr   Crossbones+   -  Reputation: 2960

Like
0Likes
Like

Posted 13 November 2012 - 10:23 PM

goto is not evil in and of itself. There are some very rare occasions when a carefully placed goto can save you a lot of time.

The problem is that goto is essentially an intrinsic for the 'jmp' instruction. If you're good with assembly and understand stack frames and the general behavior of the compiler then you can get away with it, but otherwise just do whatever you have to do to avoid it. The risk of unexpectedly dragging invalid state into somewhere that it doesn't belong (and not having the correct state established for that location) is simply too great.

Even if you do have a perfect grasp of the mechanics and implement a correct use of goto then you'll probably only do it either as a temporary measure or else as some form of bizarre optimization accompanied by 3 pages of commenting.
void hurrrrrrrr() {__asm sub [ebp+4],5;}

There are ten kinds of people in this world: those who understand binary and those who don't.

#27 Aliii   Members   -  Reputation: 1445

Like
0Likes
Like

Posted 14 November 2012 - 06:10 AM

If goto would be that bad it wouldnt exist. Its better not to use it for jumping through long code though .....especially if many people are working on the same code.
+(Ive worked at 2 big companies ....neither allowed to use goto:))

#28 rnlf   Members   -  Reputation: 1117

Like
0Likes
Like

Posted 14 November 2012 - 10:08 AM

Aliii: Some things exist as an evil legacy from the dark times.

my blog (German)


#29 SiCrane   Moderators   -  Reputation: 9554

Like
1Likes
Like

Posted 14 November 2012 - 10:59 AM

As far as I know there is no case where a goto in C++ is the best tool for the job.

The only thing I can think of is for the output of automatic code generators such as lexers and parsers. It produces unmaintainable spaghetti code, but it doesn't matter because it's not meant to be maintained by human hands.

#30 yoni0505   Members   -  Reputation: 109

Like
1Likes
Like

Posted 14 November 2012 - 01:28 PM

Basically there's no reason to use "goto" unless your code's workflow is incorrect.

#31 Aliii   Members   -  Reputation: 1445

Like
0Likes
Like

Posted 14 November 2012 - 02:04 PM

Aliii: Some things exist as an evil legacy from the dark times.


I know that. But theres no "dark times" here ....many people are just allergic to goto I think:)

#32 Radikalizm   Crossbones+   -  Reputation: 2823

Like
0Likes
Like

Posted 14 November 2012 - 02:18 PM


Aliii: Some things exist as an evil legacy from the dark times.


I know that. But theres no "dark times" here ....many people are just allergic to goto I think:)


People don't just avoid code mechanisms without a reason, in my experience there's always a better and cleaner way to solve a problem than by using goto.
And there are definitely "dark ages", C and C++ have been around for quite a while now, and both languages have evolved a lot, so it's only natural that there are features in both which have somewhat of a legacy.

I gets all your texture budgets!


#33 Orangeatang   Members   -  Reputation: 1455

Like
0Likes
Like

Posted 14 November 2012 - 03:20 PM

I think you've probably got your answer by now, but just to give my two cents - the use of GOTO in C++ can completely undermine the object oriented design of the language, which is after all the whole point.

#34 Aliii   Members   -  Reputation: 1445

Like
0Likes
Like

Posted 14 November 2012 - 04:07 PM



Aliii: Some things exist as an evil legacy from the dark times.


I know that. But theres no "dark times" here ....many people are just allergic to goto I think:)


People don't just avoid code mechanisms without a reason, in my experience there's always a better and cleaner way to solve a problem than by using goto.
And there are definitely "dark ages", C and C++ have been around for quite a while now, and both languages have evolved a lot, so it's only natural that there are features in both which have somewhat of a legacy.


It always worked fine for me. I wonder how many of those people who blame it actually used it and had all those horrible things happen to them ...and to their code. (Maybe no one:)

Of course dont use it when working in a team, dont use it in functions that are more than lets say 60 lines, ....and dont combine it with lots of break, continue, recursion and function pointers.

#35 Radikalizm   Crossbones+   -  Reputation: 2823

Like
0Likes
Like

Posted 14 November 2012 - 04:47 PM

*snip*


It's already a warning sign if you have to make a list of some quite common and maybe essential language features you shouldn't use together with goto, just saying.

Here's another one for the list:
Using goto statements can make it really damn hard to prove the correctness of your program since it completely allows you to break your program's structure. Not being able to prove that your program works as it's supposed to will send you straight to debugging hell, and that's one place you really don't want to be.

Maybe using lots of goto statements works for you, but I can think of hundreds of designs which would also work but which would be horrible to maintain, extend and debug. We don't advise against using goto because we have some sort of weird prejudice against it, we advise against it because when it comes to C++ in almost all the cases there's a better and cleaner tool for the job.


And no I'm going to stop, I'm starting to ramble...

I gets all your texture budgets!


#36 Aliii   Members   -  Reputation: 1445

Like
0Likes
Like

Posted 14 November 2012 - 06:38 PM

"It's already a warning sign if you have to make a list of some quite common and maybe essential language features you shouldn't use together with goto, just saying."
....it was not a Dont-use-this-with-goto-Bible and I didnt have to make it:) ....I just gave some examples.(I think they are quite accurate though.) Plus I used the words "lots of" but nevermind

"Maybe using lots of goto statements works for you"
It doesnt, because I dont use lots of goto.

I dont wanna argue, Ive just told my experiences with goto. You almost seem like atacking me for it.

#37 Khatharr   Crossbones+   -  Reputation: 2960

Like
0Likes
Like

Posted 14 November 2012 - 06:59 PM

It seems like people are mostly agreeing that goto should be avoided whenever possible and the program structure questioned otherwise.

Hopefully we don't need another 'little scene'. (Though I have to admit they can be pretty amusing.)
void hurrrrrrrr() {__asm sub [ebp+4],5;}

There are ten kinds of people in this world: those who understand binary and those who don't.

#38 ~   Members   -  Reputation: 103

Like
0Likes
Like

Posted 14 November 2012 - 10:29 PM

As long as a language has goto, it isn't intrinsically bad to use it.

It is possible to use it either in a right or in a wrong way.

The thing is that as a language has a higher level than others, it is in general spontaneously easier and natural to avoid using goto.

__________________________________________________
__________________________________________________
__________________________________________________
I am currently mainly an x86 Assembly language programmer but I can program a bit of C, Pascal, and a good amount of JavaScript and PHP, so I can tell you that in languages higher than Assembly (including C) I rarely use goto. It might seem paradoxical but Assembly language has helped me no end to find ways to program very elegantly and concisely without using goto, or excessive nested ifs or nested function calls.

Now, I find myself all the time converting higher-level code to Assembly by hand. In that case, you can see that down to the bare metal level all of your loops, conditional code and the like, must be converted to conditional Assembly instructions that work exactly like goto, and in general it can't be avoided at that point (which by the way is by no means an obsolete environment but just the very essence of a machine).

I also find myself converting Assembly code to higher-level code, and in this case I must find ways to do it efficiently. I almost never need to use goto when doing this.

In other words, knowing how to use goto properly is necessary, not to be abused and not to be ignored either (specially if you know and want to use Assembly language, among other things, to work a little bit in designing or understanding compiler-like programs that generate Assembly code).

If you use it too much in a high-level language, chances are that you are still in a very incipient level of knowledge for a proper implementation of your logic when you could use syntax elements better suited for what you want to achieve in that language (e.g., using goto for no special reason when you could have used a while loop that maybe you just didn't know how to use).

#39 Khatharr   Crossbones+   -  Reputation: 2960

Like
0Likes
Like

Posted 15 November 2012 - 12:09 AM

It might seem paradoxical but Assembly language has helped me no end to find ways to program very elegantly and concisely without using goto, or excessive nested ifs or nested function calls.


I've also noticed this in my own coding. I think part of it is the inversion of the logic with conditional jumps. Somehow just doing a little bit of work with that subconsciously reorganized my brain and now my loops and conditionals come out smoother. It's strange that the inversion is unintuitive but somehow results in a better 'natural flow' once it's understood.
void hurrrrrrrr() {__asm sub [ebp+4],5;}

There are ten kinds of people in this world: those who understand binary and those who don't.

#40 joshLangley   Members   -  Reputation: 123

Like
0Likes
Like

Posted 15 November 2012 - 03:18 AM

Only skimmed through the topic,

In a game menu scenario I would go with a finite state machine of game states and loop through it accordingly.
kind regards,Josh Langley.




Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.



PARTNERS