is delete[] necessary?

J

John Brawley

"John Brawley"

(I'm not sure if this is acceptable Netiquette), but;

I wanted all who trailed this thread I opened, to know I am _extremely_
thankful for your help, and that as the thread grew, I learned more and
more. (I am still following your diverged discussions and studying your
words carefully.)

I now realize perhaps I should have started here, instead of pounding the
'net for weeks and weeks looking for tutorials and such.

Thank you very much indeed.
 
K

Krice

if a general concensus before your post is that in my specific
case it _isn't_ absolutely necessary, but you enter with a
simple "yes" and a comment and no 'why' to the 'yes'?

Because it's a language feature. Besides if you forget delete
it may cause a corruption of some kind. Bad thing.
 
J

John Brawley

Krice said:
Because it's a language feature. Besides if you forget delete
it may cause a corruption of some kind. Bad thing.

Thank you.
And thanks to all.
(I'll leave the delete in.)
 
G

Gerhard Fiedler

To rewrite this using the original names, you'd get:

apiType result = callSomeApi() ;
while ( someCondition( result ) ) {
callSomeOtherApi( result ) ;
result = callSomeApi() ;
}

Notice that despite the superficial similarity in the initializataion and
the update, in C++, they are two very different operations:
initialization and assignment. C++ (more than many languages) actually
recognizes this difference: initialization (constuctor) establishes
object invariants (supposing nothing previously), assignment supposes
that the invariants hold.

This seems to be an artificial distinction (the one between initialization
and assignment) that depends on whether the variable result has been
declared before or not -- which can be relevant for some problems, but has
nothing to do with the loop structure itself.

apiType resource;
// some other code -- or not
resource = callSomeApi() ;
while ( someCondition( resource ) ) {
callSomeOtherApi( resource ) ;
resource = callSomeApi() ;
}

With a small rewrite, the distinction just goes away and we end up with the
classical duplicated code that has its own maintenance pitfalls. While
there is actually no break in this solution, it sure doesn't look any
clearer than the break solution. So what's the motivation for introducing
the duplication? We all know that this is not good, so there needs to be
some gain to offset the (even if arguably small) downside.

apiType resource;
// some other code -- or not
while ( true ) {
resource = callSomeApi() ;
if ( someCondition( resource ) )
break;
callSomeOtherApi( resource ) ;
}

Gerhard
 
J

Jerry Coffin

[ ... ]
OTOH, abs(((a + b) + c) - (a + (b + c))) < epsilon can be safe, with
appropriate choice of epsilon.

True -- with the proviso that if you make epsilon a constant, it will
usually be wrong unless you have a _very_ good idea of the magnitudes of
a and b.
 
J

Jerry Coffin

[ ... ]
I'm not sure that that's totally true. There have been some
actual experiments with some minor details---I seem to recall
reading about one showing that new programmers learned a
language faster and made less errors when statements were
terminated (as in C/C++) rather than separated (as in Pascal).

I probably did overstate the situation -- though I think only a little
bit.
But I don't think that there have been such studies for larger
scale issues, such as this. Except indirectly, perhaps: the
percentage of companies forbidding such use rises with the SEI
maturity level, for example. But that doesn't say much about
cause and effect. And I'm not sure that such information is
actually available, either. All I can say is that in the
companies I've been in, a rise in the SEI maturity level has
been accompanied with stricter coding guidelines, and that
forbidding break except in a switch has been part of the
strictest guidelines.

That wouldn't surprise me -- though I'm the first to admit that there
are probably times that restrictions are imposed with little real
reason, and some of them may even be counterproductive.

[ ... ]
On the other hand, a lot of us have had to maintain code which
didn't respect them, and that's left a very bad taste in our
mouths.

That would certainly include me as well. I'm not so zealous that I'd go
so far as to say all possible uses of break outside of a switch
statement are bad -- but it's not much short of that.

[ ... ]
I'm not sure that I like the embedded assignment, at all.

Well, I suppose that could be just a matter of accustomization, but
having used C's I/O library for years, I don't find the embedded
assignment problematic at all.
I think the real problem is that the break-up into different
functions is wrong. But without any concrete semantics, how can
you say. I would guess, however, that in most cases, something
like the standard istream idiom would be more appropriate:

while ( callSomeApi( result ) ) {
doSomethingWith( result ) ;
}

This sometimes works about as well, but other times is clearly inferior.
One obvious example would be a truly simple bit of copying in C:

while (0!=(num=fread(infile, size, sizeof(buffer), &buffer)))
write(outfile, size, num, buffer);

that becomes relatively clumsy using iostreams.
It's very much standard practice to have a function with side
effects return a success/failure indication, which can be used
as a condition in a loop or if. I'm not overly thrilled by
anything in the condition having side effects, but in this case,
it's so ubiquious, I think I'll have to live with it.

While I can sympathize with the idea of eliminating side-effects in such
situations, I think the cure is usually worse than the disease. In
particular, it's often _extremely_ useful to carry out an operation and
test for its success/failure as a single more-or-less atomic operation
(i.e. not atomic from a viewpoint of threading and such, but still
atomic from its own viewpoint).

[ ... ]
To rewrite this using the original names, you'd get:

apiType result = callSomeApi() ;
while ( someCondition( result ) ) {
callSomeOtherApi( result ) ;
result = callSomeApi() ;
}

Or:

for (apiType result=callSomeApi();
someCondition(result);
result=callSomeApi())
{
callSomeOtherApi(result);
}

I realize some people use for-loops only for simple counted loops. I
generally prefer then if you have to carry out at least two of the three
operations they define (i.e. initialization, test and update). In this
case, we clearly have all three...

[ ... ]
Never. In this case, the cure is worse than the disease. If
you need the comma operator, beware.

I have to disagree -- I'll openly admit that fixing (or wrapping) the
function is a better solution, but I'd still take this over the original
code without a second thought. There's not a thing in the world wrong
with the comma operator...
 
J

Jerry Coffin

[ ... ]
This seems to be an artificial distinction (the one between initialization
and assignment) that depends on whether the variable result has been
declared before or not -- which can be relevant for some problems, but has
nothing to do with the loop structure itself.

I don't think it's an artificial distinction at all. There's a
substantial difference between creating something and changing something
that already exists. Most languages don't really give you the access
necessary to create something directly, so you get used to the idea that
you always create something with some sort of default initialization,
then change it to what you want.

I think most languages got it wrong: if you had to choose only one way
to allow, you should require that all variables always be initialized.

[ ... ]
With a small rewrite, the distinction just goes away and we end up with the
classical duplicated code that has its own maintenance pitfalls. While
there is actually no break in this solution, it sure doesn't look any
clearer than the break solution. So what's the motivation for introducing
the duplication? We all know that this is not good, so there needs to be
some gain to offset the (even if arguably small) downside.

apiType resource;
// some other code -- or not
while ( true ) {
resource = callSomeApi() ;
if ( someCondition( resource ) )
break;
callSomeOtherApi( resource ) ;
}

But this only arises in the first place because callSomeApi has a lousy
interface and you've separated someCondition out into a separate
function, so you can't directly tell whether callSomeApi succeeded or
not.

You're simply taking a bad design and compounding its problems.
 
J

James Kanze

On 2008-01-29 08:40:34, James Kanze wrote:
By "best" you mean with the least amount (that is, no) break.
But that is circular reasoning... this type of loop in this
form is clear, easily understandable and maintainable and
wouldn't gain anything by combining parts of it into a
separate function just to get rid of the break (and even less
by using C-style obfuscation techniques; joining several
statements into a single expression :)

You misunderstood what I said. I said that given a concrete
case, it almost always turns out more logical to break up the
functions differently. In fact, of course, the real argument
against break (in this case---there are lots of abuses which are
worse, and where there are flagrant arguments against it)
involves reasoning about loop invariants.

[...]
You seem to say here that the only loop you find "good" is the while loop
(with the condition at the top). So no condition in the middle, and also
not at the end?
Yes.
The example was probably a bit too simplified.
uint8_t *buf;
uint32_t size;
for(;;)
{
size = getBuffer( buf );
if( size >= whatWeNeed )
break;
increaseBuffer();}
// work on buf
I know that this can be "simplified" in some obfuscated early
C style manner. I agree with Alf and don't really find that
clearer.

I don't see where using a function getBuffer( buf, whatWeNeed )
would be obfuscation in an early C style manner. This is very
much a case of what I said at the start---given any real
concrete example, better solutions (in the sense of "more
natural" or "more readable") will immediately occur which don't
involve the break.
It also can be rewritten by duplicating any part of it. Again,
it is a question of personal style and not generally accepted
practice to do it one way or the other (which is my point).
They are not the only ones (maybe do the search... there are a
few relevant results with relevant examples). Point is it
doesn't seem unanimous that "break is bad".

Try using some software. I think you'll find that it isn't
unanimous that "programs should work", either. The two are
related. I work (or have worked) on code that had to work. And
it is fairly unanimous that if the code has to work, you don't
use break in the middle of a loop.

[...]
The thing with the break in the middle is that there is
generally no loop invariant, if I understand you correctly
here.

More or less. And the fact that when there is no loop
invariant, the code isn't correct.
But better -- in the sense of "fits the requirements". If a
break or a goto helps to do that, then it is "good
programming" in my book. Which was simply to counter the
"never" part of the argument (as in "never say never" :)

One of the requirements for most of my code is that it work
reliably. Meeting that requirement means serious code review,
avec verification of loop invariants, etc. Breaking out of the
middle of a loop makes this analysis significantly more
difficult, and thus reduces the quality of the code.
 
G

Gerhard Fiedler

I don't think it's an artificial distinction at all.

It is not, in a general case, but it is WRT the question how to shape the
loop. It has nothing to do with the loop structure. Instead of "artificial
distinction" I could have said "strawman".
But this only arises in the first place because callSomeApi has a lousy
interface and you've separated someCondition out into a separate
function, so you can't directly tell whether callSomeApi succeeded or
not.

This is a 3rd party API, and just "is". The question is not whether that
API is good or not, it is how to best work with it.

Gerhard
 
G

Gerhard Fiedler

I don't see where using a function getBuffer( buf, whatWeNeed )
would be obfuscation in an early C style manner.

Ok, still too simplified... whatWeNeed gets determined based on what
getBuffer returns, so it's actually closer to another version of the loop I
had earlier. getBuffer() doesn't know about the internals of what's in the
buffer, so it can't by itself determine when the buffer is big enough.
weGetEnough() also doesn't know beforehand how much is enough; only after
examining the buffer contents it can tell whether it was enough or not --
and it won't know how much more it will need. The loop structure reflects
the problem structure, and the problem structure has an exit in the middle.
Anybody working on the problem understands that immediately, because the
loop structure reflects the problem structure.

uint8_t *buf;
uint32_t size;
for(;;) {
size = getBuffer( buf );
if( weGotEnough( buf, size ) )
break;
increaseBuffer();
}

This is very much a case of what I said at the start---given any real
concrete example, better solutions (in the sense of "more natural" or
"more readable") will immediately occur which don't involve the break.

Possibly. But while "more natural" and "more readable" have some objective
components, they also have plenty of subjective components. They also have
problem domain components, that are not specific to the programming
paradigm but to the problem domain.
Try using some software. I think you'll find that it isn't unanimous that
"programs should work", either. The two are related. I work (or have
worked) on code that had to work. And it is fairly unanimous that if
the code has to work, you don't use break in the middle of a loop.

I only work on code that has to work. And I do use break in the middle of a
loop occasionally -- when the structure of the problem is like this. I try
to adapt the program structure to the problem structure, not the other way
round. That approach works, too.
More or less. And the fact that when there is no loop invariant, the
code isn't correct.

Who says that there has to be a loop invariant? Of course, if you imply
that a loop has to have a loop invariant, a break in the middle becomes a
stranger. But why that requirement?
One of the requirements for most of my code is that it work reliably.
Meeting that requirement means serious code review, avec verification of
loop invariants, etc. Breaking out of the middle of a loop makes this
analysis significantly more difficult, and thus reduces the quality of
the code.

Maybe not if the loop structure correctly reflects the actual problem
structure. In those cases, transforming the problem structure into
something else may make the code more difficult to understand and the
additional, unnecessary structural transformation brings in another point
of failure.

Gerhard
 
G

Gerhard Fiedler

It has a place in switch statements, but that's about the only place it
would be allowed in good programming. For it's use in loops, of course,
it's been recognized as bad programming practice for a long time.

Back to the roots of this question... Can you cite a widely recognized and
actually used coding standard that agrees with you? I've looked into the
C++ FAQ (the one that comes with this newsgroup) and the coding standards
it cites. None of them (at least none that I could find) seems to agree
with you.

<http://www.codingstandard.com/HICPPCM/Section_5_Control_Flow.html> doesn't
explicitly talk about breaks in loops, but the one-and-a-half loop we've
been talking about conforms to these rules.

<http://www.possibility.com/cpp/CppCodingStandard.html> say that break
should be "used sparingly", which is not quite the same as "bad programming
practice". More to the point, the reason given for why it's bad when it's
bad doesn't apply to properly written one-and-a-half loops (because the
reader is not "beamed to god knows where" in a loop with, say, ten lines of
body).

<http://hem.passagen.se/erinyq/industrial/> specifically recommends the use
of break (in rule 4.6).

<http://membres.lycos.fr/pierret/cpp2.htm> specifically recommends the use
of break instead of introducing additional flags.

I already understood that these are probably not the guidelines you are
using -- but they seem to be widely recognized, or else why would they be
in the C++ FAQ? So where are the guidelines that recommend otherwise?

Gerhard
 
G

Gianni Mariani

Gerhard said:
On 2008-01-27 12:02:46, James Kanze wrote (in "is delete[] necessary?"): ....

I already understood that these are probably not the guidelines you are
using -- but they seem to be widely recognized, or else why would they be
in the C++ FAQ? So where are the guidelines that recommend otherwise?

If break is bad - I wonder what an exception is ?
 
D

Daniel T.

Gerhard Fiedler said:
James Kanze wrote (in "is delete[] necessary?"):
It has a place in switch statements, but that's about the only
place it would be allowed in good programming. For it's use in
loops, of course, it's been recognized as bad programming
practice for a long time.

Back to the roots of this question... Can you cite a widely
recognized and actually used coding standard that agrees with you?
I've looked into the C++ FAQ (the one that comes with this
newsgroup) and the coding standards it cites. None of them (at
least none that I could find) seems to agree with you.

'break' and 'continue' are "effectively restricted forms of the goto
statement."[1] As such, they suffer some of the same criticism levied
against the goto statement 40 years ago[2]. As long as 34 years ago,
McCabe defined "structured programming" as a program that does not
branch out of or into any loop or decision and gave insight into why
non-structured program logic can often become "convoluted and
entwined"[3]. So Michael and James' comments about them being "bad
programming" has a very long history.

That said, the C and by extension the C++ philosophy (and thus
guidelines) generally require single entry, but allow multiple exists
from a block of code. Although the language doesn't require even this
(note for example Duff's Device's use of a switch statement to jump into
the middle of a loop block, goto and longjmp also allow jumping into the
middle of a block. The latter even allows jumping into the middle of a
function.)

I personally never use continue, and only use break at the end of case
blocks (and in those cases I always use it, never letting the PC "fall
through" to the next case block.) But I do, on occasion, use early
return statements to jump out of the middle of a block so I can't say
I'm dogmatic about it. :)

[1] http://en.wikipedia.org/wiki/GOTO
[2] Dijkstra, "Go to statement considered harmful"
[3] McCabe, "A Complexity Measure"
 
J

Jerry Coffin

[ ... ]
This is a 3rd party API, and just "is". The question is not whether that
API is good or not, it is how to best work with it.

The best way to work with such a thing is to wrap up the call. Just for
example, you could do something like this:

bool callApiDecently(apiType &res) {
res = callSomeApi();
return someCondition(res);
}

With a wrapper like this, the loop becomes simple and straightforward:

while (callApiDecently(result))
callSomeOtherApi(result);

James Kanze previously posted the same general idea to this thread. I
don't recall his including the code for the wrapper, but I suspect this
is fairly close to the sort of thing he had in mind.

of course, as I mentioned in a previous post in this thread, there are
other possibilities as well. The point isn't that this is the only way
to fix the interface -- only that it's an interface that clearly needs
fixing.

As I said previously, I don't have anything like a religious zeal for
eliminating goto's in all possible forms. I find, however, that they
_usually_ result from badly designed code. Your example fits that
precisely.
 
J

Jerry Coffin

[ ... ]

Here I have to disagree -- while they're certainly a lot less common,
there are situations that call for a loop that executes one or more
times. In this case, a do...while loop is the natural implementation,
and putting the condition at the end makes sense. In other languages the
same is true (e.g. Pascal's repeat...until construct).

[ ... ]
Try using some software. I think you'll find that it isn't
unanimous that "programs should work", either. The two are
related. I work (or have worked) on code that had to work. And
it is fairly unanimous that if the code has to work, you don't
use break in the middle of a loop.

I can only wish I could disagree with this -- unfortunately, it's quite
clear that for many (most?) developers, software that's finished and
sort of working is better than software that (ever) really works.

[ ... ]
One of the requirements for most of my code is that it work
reliably. Meeting that requirement means serious code review,
avec verification of loop invariants, etc. Breaking out of the
middle of a loop makes this analysis significantly more
difficult, and thus reduces the quality of the code.

I don't think it _necessarily_ reduces the quality of the code -- but it
increases the expense of producing code of a specific quality. You save
a tiny bit of time in writing the code, but before you have a finished
product, you've almost certainly wasted more than you initially saved --
false economy at its worst.
 
A

Andrew Koenig

'break' and 'continue' are "effectively restricted forms of the goto
statement."[1] As such, they suffer some of the same criticism levied
against the goto statement 40 years ago[2].

Yes, but.

I went back and reread [2] not too long ago. Dijkstra makes two main
arguments against goto, neither of which applies with nearly the same force
to break or continue.

His first argument is that every goto requires a label, and it is difficult
to determine by inspection what claims you can make about the state of a
program when execution passes a label. The reason, of course, is that you
have to inspect the entire program to find every goto that refers to that
label, and then verify that the state of the program at that goto is what
you desire. This argument does not apply to break or continue, because
neither of them uses a label. Indeed, all you have to do is to ensure that
at each break or continue, the conditions that you expected the surrounding
block to satisfy have been satifsied.

His second argument is that it is hard to talk about the execution state
(i.e. how much progress the program has made, irrespective of the values of
its variables) of a program that uses goto statements. If there are just
loops and function calls, then all you need to keep track of this state is
the call trace and how many times each currently active loop has executed.
But if you introduce goto statements, this compact technique becomes
impossible. Instead, you have to remember everything that has happened.
Again, these objections do not apply to break or continue because they are
not nearly so disruptive of the flow of control.

So although I would agree with you that break and continue suffer some of
the criticisms of goto, I also think they are nowhere near in the same
league because of the limited ways in which they can transfer control.

Another way to see the difference is to note how easy it is to rewrite a
program that uses break or continue into one that doesn't, as opposed to how
hard it is to rewrite a program that uses goto.
 
D

Daniel T.

Andrew Koenig said:
Daniel T. said:
'break' and 'continue' are "effectively restricted forms of the goto
statement."[1] As such, they suffer some of the same criticism levied
against the goto statement 40 years ago[2].

Yes, but.

I went back and reread [2] not too long ago. Dijkstra makes two main
arguments against goto, neither of which applies with nearly the same force
to break or continue.

Neither of them applies with nearly the same force even to goto, as C
and C++ implement it. The gotos he wrote about could jump to anywhere in
the program, C gotos can only jump to somewhere in the same function.
 
F

Ferruccio Barletta

Daniel said:
Gerhard Fiedler said:
James Kanze wrote (in "is delete[] necessary?"):
On 2008-01-27 08:43:11, (e-mail address removed) wrote:
break and goto are concidered bad programming though, be
aware of that. Better is to define your loops with good
boolean expressions.
I guess I missed the part where break entered the "bad
programming". I think it has its place, but then you may think
what I'm doing is "bad programming" :)
It has a place in switch statements, but that's about the only
place it would be allowed in good programming. For it's use in
loops, of course, it's been recognized as bad programming
practice for a long time.
Back to the roots of this question... Can you cite a widely
recognized and actually used coding standard that agrees with you?
I've looked into the C++ FAQ (the one that comes with this
newsgroup) and the coding standards it cites. None of them (at
least none that I could find) seems to agree with you.

'break' and 'continue' are "effectively restricted forms of the goto
statement."[1] As such, they suffer some of the same criticism levied
against the goto statement 40 years ago[2]. As long as 34 years ago,
McCabe defined "structured programming" as a program that does not
branch out of or into any loop or decision and gave insight into why
non-structured program logic can often become "convoluted and
entwined"[3]. So Michael and James' comments about them being "bad
programming" has a very long history.

That said, the C and by extension the C++ philosophy (and thus
guidelines) generally require single entry, but allow multiple exists
from a block of code. Although the language doesn't require even this
(note for example Duff's Device's use of a switch statement to jump into
the middle of a loop block, goto and longjmp also allow jumping into the
middle of a block. The latter even allows jumping into the middle of a
function.)

I personally never use continue, and only use break at the end of case
blocks (and in those cases I always use it, never letting the PC "fall
through" to the next case block.) But I do, on occasion, use early
return statements to jump out of the middle of a block so I can't say
I'm dogmatic about it. :)

[1] http://en.wikipedia.org/wiki/GOTO
[2] Dijkstra, "Go to statement considered harmful"
[3] McCabe, "A Complexity Measure"

It was my understanding that goto was considered ok as long as the jump
was in a forward direction and was never used to enter into a loop. I
think break is fine when seen under that light, continue might be a bit
suspicious but is not commonly used anyway.

-- Ferruccio
 
J

Jerry Coffin

[ ... ]
It was my understanding that goto was considered ok as long as the jump
was in a forward direction and was never used to enter into a loop.

That depends on whose version of "ok" you follow. Some people would
forbid all gotos of any kind under any circumstances. Other people have
decided on slightly looser guidelines they consider reasonable.
I
think break is fine when seen under that light, continue might be a bit
suspicious but is not commonly used anyway.

I wouldn't consider continue any more suspicious than break. Then again,
you're right that it's only rarely used -- in fact about the only time I
can remember using it is in a loop to process files that looked
something like:

while (get_next_file(&file_info)) {
if (file_info.hidden)
continue;
// code to process file here
}

Of course you could just do:

while (get_next_file(&file_info)) {
if (!file_info.hidden) {
// code to process file here
}
}

Depending on the amount of code involved, however, this can be a bit
clumsy. I'd view it much like a fairly typical function that looks a bit
like:

ret_type func() {
if (!conditions_met())
return bad_value;
// do processing.
}
 
J

James Kanze

'break' and 'continue' are "effectively restricted forms of
the goto statement."[1] As such, they suffer some of the
same criticism levied against the goto statement 40 years
ago[2].

You might also add exceptions and returning from the middle of a
function, or calling exit(), abort() or some other function
which never returns.
Yes, but.
I went back and reread [2] not too long ago. Dijkstra makes
two main arguments against goto, neither of which applies with
nearly the same force to break or continue.
His first argument is that every goto requires a label, and it
is difficult to determine by inspection what claims you can
make about the state of a program when execution passes a
label. The reason, of course, is that you have to inspect the
entire program to find every goto that refers to that label,
and then verify that the state of the program at that goto is
what you desire. This argument does not apply to break or
continue, because neither of them uses a label. Indeed, all
you have to do is to ensure that at each break or continue,
the conditions that you expected the surrounding block to
satisfy have been satifsied.

There are, in fact, two separate issues involved here. One is
program structure, and the other is how you implement it. In
Fortran IV, you had to use goto, for example. This didn't mean
that you couldn't write well structured code. It did mean that
unless the reader was 100% sure that you had done so, there was
nothing in the language which would help in determining it.
(One of the best structured programs I ever saw was written in
Fortran IV.)

In C++, of course, there's no reason to use goto except for
unstructured control flow. (It's interesting to note that
Pascal had a goto. Most of the uses I've seen of it, however,
would be better handled by an exception in C++.)
His second argument is that it is hard to talk about the
execution state (i.e. how much progress the program has made,
irrespective of the values of its variables) of a program that
uses goto statements. If there are just loops and function
calls, then all you need to keep track of this state is the
call trace and how many times each currently active loop has
executed. But if you introduce goto statements, this compact
technique becomes impossible. Instead, you have to remember
everything that has happened. Again, these objections do not
apply to break or continue because they are not nearly so
disruptive of the flow of control.

And that argument hinges on the structure. The problem isn't
the goto per se, but what you do with it.

Break and continue do have problems here. As you say, nowhere
near as many as arbitrary goto's, but they do disrupt program
flow, and make reasoning about correctness more difficult.

In the example which started this thread, Alf very carefully (I
presume) chose an example of a loop and a half, where there was
only a single break, and that break was the only way to leave
the loop. Code that is, in fact, single entry/single exit.
Although I feel that even this code is better written with the
test up front (since that establishes a single loop invariant,
rather than having a weak invariant for part of the loop, and a
stronger one for the second part), such use of break is
certainly less disruptive than just arbitrary use, say with a
condition at the top as well.
So although I would agree with you that break and continue
suffer some of the criticisms of goto, I also think they are
nowhere near in the same league because of the limited ways in
which they can transfer control.

I think it's a question of use. Start using if's nested three
layers deep, and throw in a break in one of them, and a continue
in another, and it can be pretty disruptive as well. Used as
the single exit of a loop and a half, the only problem is the
fact that you have to deal with two different invariants in the
loop, rather than one. Still not the best solution, but not
nearly as bad as a lot of other things.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,183
Messages
2,570,968
Members
47,518
Latest member
TobiasAxf

Latest Threads

Top