×
Login Register an account
Top Submissions Explore Upgoat Search Random Subverse Random Post Colorize! Site Rules Donate
4

C++: Using goto sensibly is fine, and don't let anyone tell you otherwise

submitted by SithEmpire to C 3 weeksApr 2, 2025 17:27:15 ago (+4/-0)     (pomf2.lain.la)

https://pomf2.lain.la/f/m66t312.png

The linked image has formatting as intended originally. These are exposing so many different ways things look wrong without an official code markup tag.

The programming world at large has cast goto statements as always bad, but attempting to protect bad programmers from themselves is a cause so lost that it has six seasons and a 12-minute epilogue. Seeing someone write messy code and taking away everyone's goto is like seeing a nigger waving a handgun around and taking away everyone's handgun, failing to identify the problem either way. We don't need common sense goto control.

All programming constructs and mechanisms can be abused, such that singling out goto is pointless. Using goto can be perfectly appropriate and perfectly elegant. C/C++ has at least one case where goto appears absent a better mechanism, but I'll also show some situations where it's as well to use it.

Suppose we iterate pairs of integers i then j, but sometimes want to skip to the next i, ignoring any remaining j and any operations after the j-loop. One way to do this by jumping out and over said operations by placing a label at the end of the i-loop:

bool avoid(int i, int j);
void process(int i, int j);
void conclude(int i);

for (i=0; i<10; i++)
{
for (j=0; j<10; j++)
{
if (avoid(i, j)) goto next_i;
process(i, j);
}
conclude(i);
next_i: ;
}

This is for lack of labelled break and continue, which has been suggested many times and looks like it could actually be in the next C++ release. Until then, the official C solution is goto, and it is perfectly clear and performant. It is not better to screw around with a flag when you can just jump the flow. Making a separate inner function and returning early can be appropriate though, if it is not too arduous to pass in any local variables needed.

For a different scenario where goto is perfect, suppose we have a system state update function which must consume all the time given to it. Action functions modify the remaining time and return true if they concluded early, potentially having changed the state:

int state;

bool action_1(int✱ time_ms);
bool action_2(int✱ time_ms);
void action_idle();

void update(int time_ms)
{
update_again:
if (state ꞊꞊ 1)
{
if (action_1(&time_ms)) goto update_again;
}
else if (state ꞊꞊ 2)
{
if (action_2(&time_ms)) goto update_again;
}
else action_idle();
}

The goto-avoiding way could be a while loop and incurring an extra test whether any time remains. Probably worse than that is calling itself recursively just for re-entry with a lower amount of time. If the logic is in the position of knowing it needs to consume remaining time, just jump to the top!

Also in the context of state systems, there is nothing wrong with having multiple possible conclusions at the end of a function and a way to jump to the alternative flow, which becomes useful when multiple logic branches use it. Loosely:

{
// Function body with various decisions
// ...
return normal_result;

alt_conclusion:
// Alternative computation
// ...
return alt_result;
}

As with any mechanism, sensible use of it and sensibly-named labels are what makes it pass the readability test. Naming a label "hell" is also funny, everyone should get to do that at least once.


5 comments block


[ - ] AugustineOfHippo2 1 point 3 weeksApr 2, 2025 19:12:23 ago (+1/-0)

For your first example, it would be better to adjust the logic a bit and set j =10 to break out of the loop.

Your second example is a great way to start an infinite loop, or worse, a loop that sometimes takes a long time to complete, causing headaches and difficulties in debugging.

I’m not against goto, and use them in assembly sometimes, but they should be avoided as much as possible.

[ - ] SithEmpire [op] 0 points 3 weeksApr 2, 2025 19:16:26 ago (+0/-0)

The trouble with adjusting the iterator (or calling break) is that it'll still run the statements after the inner loop instead of skipping all the way to the next run of the outer loop!

[ - ] AugustineOfHippo2 0 points 3 weeksApr 2, 2025 21:49:28 ago (+0/-0)

that's why you would adjust the logic so that it would not. not really a big deal, as there are millions of ways to code something up, but goto really should be avoided if at all possible.

[ - ] dukey 1 point 3 weeksApr 2, 2025 18:23:13 ago (+1/-0)

The 'best' use for goto is probably breaking out of multiple nested loops. Since with the break statement you can only break out of the first loop.

[ - ] SithEmpire [op] 0 points 3 weeksApr 2, 2025 19:12:50 ago (+0/-0)

I heard something about labeled break/ continue being considered for C++ 26, with which I cannot disagree - although I'll still use goto for repeating sections of code conveniently!