How to avoid GOTO in C++

How to avoid GOTO in C++



I have read that GOTO is bad, but how do I avoid it? I don't know how to program without GOTO. In BASIC I used GOTO for everything. What should I use instead in C and C++?



I used GOTO in BASIC like this:


MainLoop:
INPUT string$
IF string$ = "game" THEN
GOTO game
ENDIF






Loops, if-then-else, etc. Just read any good book on C or C++; it probably won't mention goto in the early chapters.

– Fred Foo
Aug 3 '13 at 16:37


goto






function calls, loops, switch statements, polymorphism. I never encountered a situation where I needed goto in C++.

– juanchopanza
Aug 3 '13 at 16:38



goto






You can use goto instead of GOTO in C/C++. ;-)

– James McLaughlin
Aug 3 '13 at 16:38



goto


GOTO






Please get a good book and learn some of the language first. As you learn about things such as loops and functions you will start to realize that goto is not necessary.

– Captain Obvlious
Aug 3 '13 at 16:49



goto






Also note that in C++, goto could seriously mess things up. So it is not only less likely that you will need it in C++, it is more likely that it will break your program.

– juanchopanza
Aug 3 '13 at 17:02


goto




9 Answers
9



Usually loops like for, while and do while and functions have more or less disposed the need of using GOTO. Learn about using those and after a few examples you won't think about goto anymore.
:)


for


while


do while






Thankyou, but in BASIC i used goto to call subroutines. How do I do that in C and C++?

– I programmed HAL 9000
Aug 3 '13 at 16:43






You can not call subroutines with gotos. :)

– Devolus
Aug 3 '13 at 16:47






@user2648991 learn about functions in C and C++ and function calls. It os usually very well documented in any C/C++ beginners gude.

– DaMachk
Aug 3 '13 at 16:57



functions


function calls






actually I looked online and there is something called a tail call.

– I programmed HAL 9000
Aug 4 '13 at 1:52






Tail call si not yet something you should bother yourself about. For now learn to create an use functions properly and usage of pointers, structs, later classes (C++)... If you need help i can try and explain the usage with an email or so...

– DaMachk
Aug 4 '13 at 8:36



Consider the following piece of C++ code:


void broken()

int i = rand() % 10;
if (i == 0) // 1 in 10 chance.
goto iHaveABadFeelingAboutThis;

std::string cake = "a lie";

// ...
// lots of code that prepares the cake
// ...

iHaveABadFeelingAboutThis:
// 1 time out of ten, the cake really is a lie.
eat(cake);

// maybe this is where "iHaveABadFeelingAboutThis" was supposed to be?
std::cout << "Thank you for calling" << std::endl;



Ultimately, "goto" is not much different than C++'s other flow-control keywords: "break", "continue", "throw", etc; functionally it introduces some scope-related issues as demonstrated above.



Relying on goto will teach you bad habits that produce difficult to read, difficult to debug and difficult to maintain code, and it will generally tend to lead to bugs. Why? Because goto is free-form in the worst possible way, and it lets you bypass structural controls built into the language, such as scope rules, etc.



Few of the alternatives are particularly intuitive, and some of them are arguably as ambiguous as "goto", but at least you are operating within the structure of the language - referring back to the above sample, it's much harder to do what we did in the above example with anything but goto (of course, you can still shoot yourself in the foot with for/while/throw when working with pointers).



Your options for avoiding it and using the language's natural flow control constructs to keep code humanly readable and maintainable:



Don't be afraid of small, discrete, well-named functions, as long as you are not perpetually hauling a massive list of arguments around (if you are, then you probably want to look at encapsulating with a class).



Many novices use "goto" because they write ridiculously long functions and then find that they want to get from line 2 of a 3000 line function to line 2998. In the above code, the bug created by goto is much harder to create if you split the function into two payloads, the logic and the functional.


void haveCake()
std::string cake = "a lie";

// ...
// lots of code that prepares the cake
// ...

eat(cake);


void foo()
int i = rand() % 10;
if (i != 0) // 9 times out of 10
haveCake();
std::cout << "Thanks for calling" << std::endl;



Some folks refer to this as "hoisting" (I hoisted everything that needed to be scoped with 'cake' into the haveCake function).



These are not always obvious to programmers starting out, it says it's a for/while/do loop but it's actually only intended to run once.


for ( ; ; ) // 1-shot for loop.
int i = rand() % 10;
if (i == 0) // 1 time in 10
break;
std::string cake = "a lie";
// << all the cakey goodness.

// And here's the weakness of this approach.
// If you don't "break" you may create an infinite loop.
break;


std::cout << "Thanks for calling" << std::endl;



These can be very powerful, but they can also require a lot of boiler plate. Plus you can throw exceptions to be caught further back up the call stack or not at all (and exit the program).


struct OutOfLuck ;

try
int i = rand() % 10;
if (i == 0)
throw OutOfLuck();
std::string cake = "a lie";
// << did you know: cake contains no fat, sugar, salt, calories or chemicals?
if (cake.size() < MIN_CAKE)
throw CakeError("WTF is this? I asked for cake, not muffin");

catch (OutOfLuck&) // we don't catch CakeError, that's Someone Else's Problem(TM).

std::cout << "Thanks for calling" << std::endl;



Formally, you should try and derive your exceptions from std::exception, but I'm sometimes kind of partial to throwing const char* strings, enums and occasionally struct Rock.


try
if (creamyGoodness.index() < 11)
throw "Well, heck, we ran out of cream.";
catch (const char* wkoft /*what kind of fail today*/)
std::cout << "CAKE FAIL: " << wkoft << std::endl;
throw std::runtime_error(wkoft);



The biggest problem here is that exceptions are intended for handling errors as in the second of the two examples immediately above.






Wow...thats a lot of code for cake...

– I programmed HAL 9000
Aug 4 '13 at 2:47






"did you know: cake contains no fat, sugar, salt, calories or chemicals?" +1 for the laugh, but no. :)

– user743382
Aug 4 '13 at 21:58






@hvd caveat emptor, std::string cake = "a lie"; :)

– kfsone
Aug 4 '13 at 22:08


std::string cake = "a lie";






@kfsone - Plus one for Most entertaining

– ryyker
Sep 9 '13 at 23:15






+1 for Someone Else's Problem (TM)

– Renan Gemignani
Sep 11 '13 at 1:33


Someone Else's Problem (TM)



There are several reasons to use goto, the main would be: conditional execution, loops and "exit" routine.


goto



Conditional execution is managed by if/else generally, and it should be enough


if


else



Loops are managed by for, while and do while; and are furthermore reinforced by continue and break


for


while


do while


continue


break



The most difficult would be the "exit" routine, in C++ however it is replaced by deterministic execution of destructors. So to make you call a routine on exiting a function, you simply create an object that will perform the action you need in its destructor: immediate advantages are that you cannot forget to execute the action when adding one return and that it'll work even in the presence of exceptions.


return



Edsger Dijkstra published a famous letter titled Go To Statement Considered Harmful. You should read about it, he advocated for structured programming. That wikipedia article describes what you need to know about structured programming. You can write structured programs with goto, but that is not a popular view these days, for that perspective read Donald Knuth's Structured Programming with goto Statements.



goto is now displaced by other programming constructs like for, while, do-while etc, which are easier to read. But goto still has it's uses. I use it in a situation where different code blocks in a function (for e.g., which involve different conditional checks) have a single exit point. Apart from this one use for every other thing you should use appropriate programming constructs.


goto


for


while


do-while


goto



goto is not inherently bad, it has it's uses, just like any other language feature. You can completely avoid using goto, by using exceptions, try/catch, and loops as well as appropriate if/else constructs.


goto


goto


exceptions


try/catch


if/else



However, if you realize that you get extremly out of your way, just to avoid it, it might be an indiaction that it would be better to use it.



Personally I use goto to implement functions with single entry and exit points, which makes the code much more readable. This is the only thing where I still find goto usefull and actually improves the structure and readabillity of the code.



As an example:


int foo()

int fd1 = -1;
int fd2 = -1;
int fd3 = -1;

fd1 = open();
if(fd1 == -1)
goto Quit:

fd2 = open();
if(fd2 == -1)
goto Quit:

fd3 = open();
if(fd3 == -1)
goto Quit:

... do your stuff here ...

Quit:
if(fd1 != -1)
closefile();

if(fd2 != -1)
closefile();

if(fd3 != -1)
closefile();



In C++ you find, that the need for such structures might be drastically reduced, if you properly implement classes which encapsulate access to resources. For example using smartpointer are such an example.



In the above sample, you would implement/use a file class in C++, so that, when it gets destructed, the file handle is also closed. Using classes, also has the advantage that it will work when exceptions are thrown, because then the compiler ensures that all objects are properly destructed. So in C++ you should definitely use classes with destructors, to achieve this.



When you want to code in C, you should consider that extra blocks also add additional complexity to the code, which in turn makes the code harder to understand and to control. I would prefer a well placed goto anytime over a series of artifical if/else clauses just to avoid it. And if you later have to revisit the code, you can still understand it, without following all the extra blocks.






You might also mention, that this use of goto is actually part of the linux styleguide :-)

– cmaster
Aug 3 '13 at 16:46


goto






@cmaster, I didn't know that. :)

– Devolus
Aug 3 '13 at 16:47







Yes, this is an example where goto helps readability, but that isn't what the question asks. The question asks when not to use goto (where the OP would use GOTO in the equivalent BASIC code because of limitations of the language)

– user743382
Aug 3 '13 at 16:53


goto


goto


GOTO






In C++, this is a bad example, as it's better done using the RAII pattern. Then, you can just return or throw an exception in case something goes wrong, and cleanup happens automatically. But I agree that in C this pattern can occasionally be useful.

– Thomas
Aug 3 '13 at 16:58


return






You briefly mentioned some other points, but if I were the OP, and I were reading this answer, I would read it as "it's okay to just continue using goto". In that light, your answer is correct, but probably unhelpful. However, I cannot judge if this is how others interpret your answer as well, and if others don't, please do disregard my comment.

– user743382
Aug 3 '13 at 16:59


goto



Maybe instead of


if(something happens)
goto err;

err:
print_log()



one can use :


do

if (something happens)

seterrbool = true;
break; // You can avoid using using go to I believe


while (false) //loop will work only one anyways
if (seterrbool)
printlog();



It may not seem friendly because in the example above there is only one goto but will be more readable if there are many "goto" .



This implementation of the function above avoids using goto's. Note, this does NOT contain a loop. The compiler will optimize this. I prefer this implementation.



Using 'break' and 'continue', goto statements can (almost?) always be avoided.


int foo()

int fd1 = -1;
int fd2 = -1;
int fd3 = -1;

do

fd1 = open();
if(fd1 == -1)
break;

fd2 = open();
if(fd2 == -1)
break:

fd3 = open();
if(fd3 == -1)
break;

... do your stuff here ...

while (false);

if(fd1 != -1)
closefile();

if(fd2 != -1)
closefile();

if(fd3 != -1)
closefile();



BASIC originally is an interpreted language. It doesn't have structures so it relies on GOTOs to jump the specific line. In this way the program flow is hard to follow, making debugging more complicated.


GOTO



Pascal, C and all modern high-level programming languages including Visual Basic (which was based on BASIC) are strongly structured with "commands" grouped into blocks. For example VB has Do...Loop, While...End While, For...Next


Do...Loop


While...End While


For...Next





Similar things will be used in C++, like if, then, for, do, while... which together define the program flow. You don't need to use goto to jump to the next statement. In specific cases you can still use goto if it makes the control flow clearer, but in general there's no need for it


if


then


for


do


while


goto


goto



Thanks for contributing an answer to Stack Overflow!



But avoid



To learn more, see our tips on writing great answers.



Required, but never shown



Required, but never shown




By clicking "Post Your Answer", you agree to our terms of service, privacy policy and cookie policy

Popular posts from this blog

𛂒𛀶,𛀽𛀑𛂀𛃧𛂓𛀙𛃆𛃑𛃷𛂟𛁡𛀢𛀟𛁤𛂽𛁕𛁪𛂟𛂯,𛁞𛂧𛀴𛁄𛁠𛁼𛂿𛀤 𛂘,𛁺𛂾𛃭𛃭𛃵𛀺,𛂣𛃍𛂖𛃶 𛀸𛃀𛂖𛁶𛁏𛁚 𛂢𛂞 𛁰𛂆𛀔,𛁸𛀽𛁓𛃋𛂇𛃧𛀧𛃣𛂐𛃇,𛂂𛃻𛃲𛁬𛃞𛀧𛃃𛀅 𛂭𛁠𛁡𛃇𛀷𛃓𛁥,𛁙𛁘𛁞𛃸𛁸𛃣𛁜,𛂛,𛃿,𛁯𛂘𛂌𛃛𛁱𛃌𛂈𛂇 𛁊𛃲,𛀕𛃴𛀜 𛀶𛂆𛀶𛃟𛂉𛀣,𛂐𛁞𛁾 𛁷𛂑𛁳𛂯𛀬𛃅,𛃶𛁼

ャフサォクコ ケウ,コ,ワ メ,ロスョノ゙,クネ,フムカヤヲニ,エコ゚ツ ウイオン゙ケワサネォキモュキォウイノンコチ゚メヌナイゥフュ,カヒウネェ ネ,ホノケ,ムュキ ッボーミュハ,チ ツス ィ メウイマヤ,゙ウチ ヅ ロ,ォジヌェ ャヌット ェ,マャ,チナエヒネソキツテ トホヲヲミーァ

How do I collapse sections of code in Visual Studio Code for Windows?