Thank you all for the replies. So let me wrap it up. Basically,
the consensus we've reached here is this: many alternatives
exist, and there is no one best way to go for all cases, but
some are more suited to some situations than others. The
alternatives suggested were:
1) the code might need some refactoring
2) elegant ways might exist to trip both loops at once
3) try return statements
4) rethink datastructures to use STL algos
5) use goto
6) duplicated ifs
7) exceptions
(
Honestly, I'd NEVER use the last two options, although you might
prefer it. See the end of this post for explanations and logic.
And like I said before, Karl's solution is sometimes preferable
but I don't always... see (a) below for why.
If anyone can add to the list, I'm all ears, but this thread
seems to be going in circles now ... can we pls. move on?
In my last post, I posted a few new questions in the footnote -
no one seems to have noticed it, so let me quote it here:
That's why I was wondering if int breaks will ever be there in the
standard... so that this word would NEVER be needed EVER again! That
kind of stuffs should be faster to get into people's heads than a
*good* use of goto.
Samee
P.S. On a slightly different note of curiosity ... how are goto labels
scoped in C++? Function scoped I suppose? Is there a way of changing
the default scoping behavior of labels?
And (not that I'm planning to use it anywhere!) is there a short C++
equivalent for asm statements like "jmp [ebx]"? (I know things like
"call [ebx]" are done by function pointers)
"Pointers to labels" kind of things (I'm sure no one here has heard
of THAT
? What wierd situations can possibly make this kind of
things actually useful?
(pls. avoid snappy answers like "none" ... I already know that on my
own
Any useful answers?
------------about some of the alternatives suggested----------
I know it's strange for the OP to post answers, but I felt like
some of the replies here needed explainations as to why they are
not always appropriate.
(a) Using returns: This is one of the best ways, but I'd go
against introducing functions just for the sake of being able
to use return. This code suggested here, e.g.
void foo()
{
// some code
process_loops();
// some more code
}
void process_loops()
{
for( int i = 0; i < some_number; ++i )
for( int j = 0; j < some_other_number; ++j )
if( j_equals_some_value )
return;
}
is fine if I can read foo() and understand what it does
without having to scroll up and down to process_loops all the
time. But in the cases that's not possible, such methods are
better avoided. Over-engineering is as big a problem to
maintenance/readability as is lack of modularity. We make
functions when (i) a block of code is in frequent use (ii)
we need to be able to plug blocks into codes at random, OR
(iii) a certain block of code represents a certain distict
concept or an entire action, introducing which improves
readability/maintenance.
(b) Using duplicated ifs: When rearranging codes, it is quite
easy (at least for me) to forget to change one of the if
statements and change just the other. Silent bugs creep up
easily this way. Besides, loops nested this deep are often
tight loops where every operation matters w.r.t. speed.
Checking if the control var was changed every time the middle
loop runs makes it slow - unnecessarily so.
(c) Using exceptions: NO-NO! throw exists to return control to
an outside scope, where current scope doesn't know enough to
handle the situation. When introducing a try block, compilers
have to ready the code for a throw command from *inside* any
of the functions/methods directly or indirectly called in the
try block. A throw command, on the other hand, in a function
(where there is no try) doesn't know the destination (corresponding
catch) of the control transfer. So compilers, when producing
binary code, cannot just substitute it for a goto statement -
they don't know which catch to go to! This means a throw
statement is more complicated than a simple goto statement
and may involve run-time overheads. Misusing exceptions like
this is SLOW!
If anyone opines against what I've said here, they may of course
explain their opinions, but I'd really like to see this discussion
moving forward, instead of just sticking to this argument over
which is better! I still have some confusions, as I said in the earlier
post, about C++'s treatment of labels w.r.t. scopes and stuff.
Samee