By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
455,515 Members | 1,848 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 455,515 IT Pros & Developers. It's quick & easy.

Exiting from loop

P: n/a
If I'm having nested loops like:

for (...) for (..) for (...) { /* exit here */ }

and I need to exit from there ^ .

Is it better to use exceptions or goto or some other method?

Oct 24 '05 #1
Share this Question
Share on Google+
39 Replies


P: n/a
vineoff wrote:
If I'm having nested loops like:

for (...) for (..) for (...) { /* exit here */ }

and I need to exit from there ^ .

Is it better to use exceptions or goto or some other method?


goto.
Oct 24 '05 #2

P: n/a
vineoff wrote:

If I'm having nested loops like:

for (...) for (..) for (...) { /* exit here */ }

and I need to exit from there ^ .

Is it better to use exceptions or goto or some other method?


Create a function which holds only the nested loops and
return from that function in the innermost loop.

(Yes: it is a sort of goto, without an explicite goto)

--
Karl Heinz Buchegger
kb******@gascad.at
Oct 24 '05 #3

P: n/a
Tatu Portin wrote:
vineoff wrote:
If I'm having nested loops like:

for (...) for (..) for (...) { /* exit here */ }

and I need to exit from there ^ .

Is it better to use exceptions or goto or some other method?


goto.


I find it clearer to have a variable to indicate that it is time to
exit:

bool done = false;
for( int i=0; !done && i < 10; ++i )
{
for( int j=0; !done && j < 10; ++j )
{
for( int k=0; !done && k < 10; ++k )
{
if( k == 5 ) // Some dummy exit condition
{
done = true;
continue; // or break;
}
}
}
}

In general, you should not use exceptions unless the condition is,
well, exceptional. IOW, don't use exceptions as an alternative to break
and continue when there is not actually an error (however that is
defined).

Cheers! --M

Oct 24 '05 #4

P: n/a
* vineoff:
If I'm having nested loops like:

for (...) for (..) for (...) { /* exit here */ }

and I need to exit from there ^ .

Is it better to use exceptions or goto or some other method?


Don't use exceptions (inefficient and unorthodox and possibly dangerous), and
don't use goto (try to find the ACM web version of Dijkstra's "GOTO considered
harmful" (ah, well, Google lists it as first hit)).

As Karl Heinz Buchegger suggested, if you absolutely must _jump_, a function
return can be a tolerable solution.

However, "premature optimization is the root of all evil" (Hoare, Knuth). If
you do the proper continuation checks, and if necessary suitable break and/or
continue, the loops may become more clear to you, and also to the compiler.
Then if there was a bug it may be that it disappears, the code may become more
maintainable, and it may even run faster than with the jump...

That technical stuff aside, a triply nested loop can be indicative of a design
flaw.

What does the triply nested loop do, and how many lines in total?

--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
Oct 24 '05 #5

P: n/a
Alf P. Steinbach wrote:
* vineoff:
If I'm having nested loops like:

for (...) for (..) for (...) { /* exit here */ }

and I need to exit from there ^ .

Is it better to use exceptions or goto or some other method?

Don't use exceptions (inefficient and unorthodox and possibly dangerous), and
don't use goto (try to find the ACM web version of Dijkstra's "GOTO considered
harmful" (ah, well, Google lists it as first hit)).


My $0.02.

1. For bailing out of deeply nested loops, GOTO is not necessarily
harmful. But I don't have my copy of the Standard available, and am not
sure if a goto calls destructors when exiting blocks.

2. An exception would guarantee destructor calling, and would exit your
code, but it might be unnecessarily baroque. If you went this route,
I'd define my own exception (not part of the std::exception hierarchy):

struct loop_bailout_exception { };

3. Nested functions may be your best bet. If you're nesting that
deeply, your problem is probably refactorable as well. Your functions
could return a continue-loop/abort-loop indicator.
Oct 24 '05 #6

P: n/a
red floyd wrote:
My $0.02.

1. For bailing out of deeply nested loops, GOTO is not necessarily
harmful. But I don't have my copy of the Standard available, and am not
sure if a goto calls destructors when exiting blocks.
Gotos are horribly outdated IMO. The last place I remember using them
was in QBASIC and the BASIC compilers on Apple IIs
2. An exception would guarantee destructor calling, and would exit your
code, but it might be unnecessarily baroque. If you went this route,
I'd define my own exception (not part of the std::exception hierarchy):
But then you're using an exception as a standard part of the code. I
have a 3rd-party API library that does this, and it's such an annoyance
to view the exceptions everytime they're generated in the debugger.
3. Nested functions may be your best bet. If you're nesting that
deeply, your problem is probably refactorable as well. Your functions
could return a continue-loop/abort-loop indicator.


This is probably the best bet. Easiest way to debug and clearest to a
2nd eye.

Oct 24 '05 #7

P: n/a
red floyd wrote:
Alf P. Steinbach wrote:
* vineoff:
If I'm having nested loops like:

for (...) for (..) for (...) { /* exit here */ }

and I need to exit from there ^ .

Is it better to use exceptions or goto or some other method?

Don't use exceptions (inefficient and unorthodox and possibly dangerous),
and don't use goto (try to find the ACM web version of Dijkstra's "GOTO
considered harmful" (ah, well, Google lists it as first hit)).


My $0.02.

1. For bailing out of deeply nested loops, GOTO is not necessarily
harmful. But I don't have my copy of the Standard available, and am not
sure if a goto calls destructors when exiting blocks.


The objects are properly destroyed:
[6.6/2]
On exit from a scope (however accomplished), destructors (12.4) are called
for all constructed objects with automatic storage duration (3.7.2) (named
objects or temporaries) that are declared in that scope, in the reverse
order of their declaration. Transfer out of a loop, out of a block, or back
past an initialized variable with automatic storage duration involves the
destruction of variables with automatic storage duration that
are in scope at the point transferred from but not at the point transferred
to. (See 6.7 for transfers into blocks). [Note: However, the program can be
terminated (by calling exit() or abort()(18.3), for example) without
destroying class objects with automatic storage duration. ]

[snip]
Best

Kai-Uwe Bux

Oct 24 '05 #8

P: n/a
Josh Mcfarlane wrote:
red floyd wrote:
My $0.02.

1. For bailing out of deeply nested loops, GOTO is not necessarily
harmful. But I don't have my copy of the Standard available, and am not
sure if a goto calls destructors when exiting blocks.


Gotos are horribly outdated IMO. The last place I remember using them
was in QBASIC and the BASIC compilers on Apple IIs


You are entitled to your opinion. However, sometimes oldfashioned can be the
best tool to do a job.

2. An exception would guarantee destructor calling, and would exit your
code, but it might be unnecessarily baroque. If you went this route,
I'd define my own exception (not part of the std::exception hierarchy):


But then you're using an exception as a standard part of the code. I
have a 3rd-party API library that does this, and it's such an annoyance
to view the exceptions everytime they're generated in the debugger.


Huh? Are these exceptions to be caught by the client or to are they caught
within the library?

3. Nested functions may be your best bet. If you're nesting that
deeply, your problem is probably refactorable as well. Your functions
could return a continue-loop/abort-loop indicator.


This is probably the best bet. Easiest way to debug and clearest to a
2nd eye.


Hm, introducing a function just to avoid a goto is barock. A function should
have a well-defined purpose/meaning/contract.

There are gotos that are just fine. Generally, I consider gotos that are
just generalized break and continue statements different from those gotos
that jump all over the place.
Best

Kai-Uwe Bux
Oct 24 '05 #9

P: n/a
On 2005-10-24, Kai-Uwe Bux <jk********@gmx.net> wrote:
Josh Mcfarlane wrote:
Gotos are horribly outdated IMO. The last place I remember
using them was in QBASIC and the BASIC compilers on Apple IIs


You are entitled to your opinion. However, sometimes
oldfashioned can be the best tool to do a job.


Prompting and verifying input is a case where goto turns out to
seem nice and clean.

#include <iostream>
#include <limits>

template <typename T>
T ranged_prompt(T min, T max)
{
T n;
prompt:
std::cout << "Enter a number from " << min << " to " << max ": ";
std::cout.flush()
std::cin >> n;
if (!std::cin || n < min || n > max) {
std::cin.clear();
std::cin.ignore(std::numeric_limits<int>::max(), '\n');
goto prompt;
}
return n;
}

/* Alternative 1 */
template <typename T>
T ranged_prompt(T min, T max)
{
T n;
bool input_invalid = true;
while (input_invalid) {
std::cout << "Enter a number from " << min << " to " << max ": ";
std::cout.flush()
std::cin >> n;
if (!std::cin || n < min || n > max) {
std::cin.clear();
std::cin.ignore(std::numeric_limits<int>::max(), '\n');
} else {
input_invalid = false;
}
}
return n;
}

/* Other alternatives? */

--
Neil Cerutti
Oct 24 '05 #10

P: n/a
mlimber wrote:
Tatu Portin wrote:
vineoff wrote:
If I'm having nested loops like:

for (...) for (..) for (...) { /* exit here */ }

and I need to exit from there ^ .

Is it better to use exceptions or goto or some other method?


goto.

I find it clearer to have a variable to indicate that it is time to
exit:

bool done = false;
for( int i=0; !done && i < 10; ++i )
{
for( int j=0; !done && j < 10; ++j )
{
for( int k=0; !done && k < 10; ++k )
{
if( k == 5 ) // Some dummy exit condition
{
done = true;
continue; // or break;
}
}
}
}

In general, you should not use exceptions unless the condition is,
well, exceptional. IOW, don't use exceptions as an alternative to break
and continue when there is not actually an error (however that is
defined).


It is not efficient.
Oct 24 '05 #11

P: n/a
use break

Oct 24 '05 #12

P: n/a
Neil Cerutti wrote:
On 2005-10-24, Kai-Uwe Bux <jk********@gmx.net> wrote:
Josh Mcfarlane wrote:
Gotos are horribly outdated IMO. The last place I remember
using them was in QBASIC and the BASIC compilers on Apple IIs


You are entitled to your opinion. However, sometimes
oldfashioned can be the best tool to do a job.


Prompting and verifying input is a case where goto turns out to
seem nice and clean.

#include <iostream>
#include <limits>

template <typename T>
T ranged_prompt(T min, T max)
{
T n;
prompt:
std::cout << "Enter a number from " << min << " to " << max ": ";
std::cout.flush()
std::cin >> n;
if (!std::cin || n < min || n > max) {
std::cin.clear();
std::cin.ignore(std::numeric_limits<int>::max(), '\n');
goto prompt;
}
return n;
}

/* Alternative 1 */
template <typename T>
T ranged_prompt(T min, T max)
{
T n;
bool input_invalid = true;
while (input_invalid) {
std::cout << "Enter a number from " << min << " to " << max ": ";
std::cout.flush()
std::cin >> n;
if (!std::cin || n < min || n > max) {
std::cin.clear();
std::cin.ignore(std::numeric_limits<int>::max(), '\n');
} else {
input_invalid = false;
}
}
return n;
}

/* Other alternatives? */


Ahem, what about:

template <typename T>
T ranged_prompt(T min, T max)
{
T n;
do {
std::cout << "Enter a number from " << min << " to " << max ": ";
std::cout.flush()
std::cin >> n;
while (!std::cin || n < min || n > max) {
std::cin.clear();
std::cin.ignore(std::numeric_limits<int>::max(), '\n');
return n;
}
Best

Kai-Uwe Bux
Best

Kai-Uwe Bux
Oct 24 '05 #13

P: n/a

"vineoff" <vi*****@gmail.com> wrote in message
news:11*********************@g47g2000cwa.googlegro ups.com...
If I'm having nested loops like:

for (...) for (..) for (...) { /* exit here */ }

and I need to exit from there ^ .

Is it better to use exceptions or goto or some other method?


I'm sure you have a good reason to put all those loops inside eachother
(like e.g. iterating through something three dimensional) - I would
definately go for a goto in this case.

Goto is not dangerous or evil, it's just easy to use in ways that mess up
your code. But it is a clear and precise way of exiting nested loops if you
have found what you are looking for.

To me it seems people tend to forget why they should not use goto, and just
refrain from using it because their teachers told them not to. You should
always consider the solution which creates clear and understandable code
which is easy to maintain.

Best regards,
Mogens
Oct 24 '05 #14

P: n/a
* Kai-Uwe Bux -> Neil Cerutti:

Ahem, what about:

template <typename T>
T ranged_prompt(T min, T max)
{
T n;
do {
std::cout << "Enter a number from " << min << " to " << max ": ";
std::cout.flush()
std::cin >> n;
while (!std::cin || n < min || n > max) {
std::cin.clear();
std::cin.ignore(std::numeric_limits<int>::max(), '\n');
return n;
}


Typos, typos... ;-)

Possibly you meant something like

template< typename T >
T numberFromUser( T min, T max )
{
T n;
bool ok;

do
{
std::cout << "Enter a number from " << min << " to " << max ": ";
std::cin >> n; // cin and cout are synchronized.
ok = (std::cin.good() && min <= n && n <= max);
std::cin.clear();
std::cin.ignore( std::numeric_limits<int>::max(), '\n' );
} while( !ok );
return n;
}

One crucial thing here is the name change, to reflect what the function
produces. I don't think I could guess from the name 'ranged_prompt' (the OP's
choice) that it actually does input. I'd guess it produced a prompt.

Of course for good measure -- less Undefined Behavior, those iostreams
aren't my favorite beasts! -- one should read in a whole line using getline,
and parse it using strtol or strtod as appropriate (not a stringstream)...

--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
Oct 24 '05 #15

P: n/a
Alf P. Steinbach wrote:
* Kai-Uwe Bux -> Neil Cerutti:

Ahem, what about:

template <typename T>
T ranged_prompt(T min, T max)
{
T n;
do {
std::cout << "Enter a number from " << min << " to " << max ": ";
std::cout.flush()
std::cin >> n;
while (!std::cin || n < min || n > max) {
std::cin.clear();
std::cin.ignore(std::numeric_limits<int>::max(), '\n');
return n;
}


Typos, typos... ;-)

Possibly you meant something like

template< typename T >
T numberFromUser( T min, T max )
{
T n;
bool ok;

do
{
std::cout << "Enter a number from " << min << " to " << max ":
";
std::cin >> n; // cin and cout are synchronized.
ok = (std::cin.good() && min <= n && n <= max);
std::cin.clear();
std::cin.ignore( std::numeric_limits<int>::max(), '\n' );
} while( !ok );
return n;
}

One crucial thing here is the name change, to reflect what the function
produces. I don't think I could guess from the name 'ranged_prompt' (the
OP's
choice) that it actually does input. I'd guess it produced a prompt.


As for the name: it actually prompts.

Anyway, I meant to get rid of the goto without introducing a flag variable.
So here:

template <typename T>
T ranged_prompt(T min, T max)
{
T n;
do {
std::cout << "Enter a number from " << min << " to " << max << ": ";
std::cout.flush();
std::cin >> n;
if (!std::cin || n < min || n > max) {
std::cin.clear();
std::cin.ignore(std::numeric_limits<int>::max(), '\n');
continue;
}
} while ( false );
return n;
}

Now, one could argue that continue is just as bad as a goto. Well, here
goes:

template <typename T>
T ranged_prompt(T min, T max)
{
T n;
do {
std::cout << "Enter a number from " << min << " to " << max << ": ";
std::cout.flush();
std::cin >> n;
} while ( (!std::cin || n < min || n > max)
? std::cin.clear(),
std::cin.ignore(std::numeric_limits<int>::max(), '\n'),
true
: false );
return n;
}

Mission complete: goto-like jumps avoided <g>
Best

Kai-Uwe Bux
Oct 24 '05 #16

P: n/a
I always find it interesting in which ways coders react on the
mention of "goto". Yes it is quick and dirty, but IMHO sometimes
pragmatism should be favoured over academical correctnes. And
there are some situations in which a "goto" is the most readable
and clear way to go. A good example would be the initialization
of a device driver (ok, those are normally done in C and not
C++). If something goes wrong there you must make sure that you
revert the state of the device on how you found it.

enum subdevice{A, B, C};

bool init_device()
{
sub_device_status pre_A;
sub_device_status pre_B;
sub_device_status pre_C;

// each init_subdevice_ call initializies the
// internal data structures and then reset the
// subdevice

get_device_status(A, &pre_A);
if( !init_subdevice_A() )
goto failed_A;

get_device_status(B, &pre_B);
if( !init_subdevice_B() )
goto failed_B;

get_device_status(C, &pre_C);
if( !init_subdevice_C() )
goto failed_C;

// All subdevices got initialized properly
return true;

failed_C:
set_device_status(C, pre_C);
failed_B:
set_device_status(B, pre_B);
failed_A:
set_device_status(A, pre_A);

return false;
}

Frankly I don't know a cleaner way to write this, but I'm open to
other suggestions. Also there are situations in which one has
deeply nested loops and where splitting in seperate functions is
inapropriate. An example may be the processing of a large
multidimensional array. And even if premature optimization is
considered bad there are some things that one can still do to
enhance performance.

For example to do as few function calls as possible. Each C/C++
function call requires to push stuff on the stack, modify the
stack pointer, then the instruction pointer and probably also
blows the registers. If you google in the NGs which deal with
time critical programming (e.g. interactive computer graphics)
one common rule is to do as few function calls and do as much
data processing within a single function as possible. Of course
I'm not saying: "Put everything in main", but splitting
functions until they are sliced to hundreds of trivial 2 liner
functions in C/C++ is IMHO as bad. If you want to go for this
use a functional programming language, they're designed for
this.

Wolfgang Draxinger
--

Oct 24 '05 #17

P: n/a
* Kai-Uwe Bux:
* Alf P. Steinbach wrote:
* Kai-Uwe Bux -> Neil Cerutti:

Ahem, what about:

template <typename T>
T ranged_prompt(T min, T max)
{
T n;
do {
std::cout << "Enter a number from " << min << " to " << max ": ";
std::cout.flush()
std::cin >> n;
while (!std::cin || n < min || n > max) {
std::cin.clear();
std::cin.ignore(std::numeric_limits<int>::max(), '\n');
return n;
}
Typos, typos... ;-)

Possibly you meant something like

template< typename T >
T numberFromUser( T min, T max )
{
T n;
bool ok;

do
{
std::cout << "Enter a number from " << min << " to " << max ":
";
std::cin >> n; // cin and cout are synchronized.
ok = (std::cin.good() && min <= n && n <= max);
std::cin.clear();
std::cin.ignore( std::numeric_limits<int>::max(), '\n' );
} while( !ok );
return n;
}

One crucial thing here is the name change, to reflect what the function
produces. I don't think I could guess from the name 'ranged_prompt' (the
OP's
choice) that it actually does input. I'd guess it produced a prompt.


As for the name: it actually prompts.


Well, but it does more than that, doesn't it?

As I see it that prompt business is a secondary thing.

Anyway, I meant to get rid of the goto without introducing a flag variable.


Note what the flag is used for: to remember the goodness of the stream until
after the stream has been cleared and line emptied.

Which IMHO should be done regardless of success or failure this iteration.

If the flag variable is removed and replaced by a position in the code, then
without using RAII I think there will necessarily be code duplication: the
cleanup actions duplicated for the cases of success and failure for this
iteration.

The simplest RAII would be to use a ScopeGuard object, but that brings in the
whole ScopeGuard header, which is too much to present here.

A Do-It-Yourself RAII-based version might go like this:

class StreamCleanup
{
private:
std::istream& myStream;
StreamCleanup& operator=( StreamCleanup const& ); // None.
public:
StreamCleanup( std::istream& s ): myStream( s ) {}
~StreamCleanup()
{
myStream.clear();
myStream.ignore( std::numeric_limits<int>::max(), '\n' );
}
};

template< typename T >
T numberFromUser( T min, T max )
{
for( ;; )
{
StreamCleanup cleaner( std::cin );
T n;

std::cout
<< "Enter a number from " << min << " to " << max << ": ";
std::cin >> n; // cin and cout are synchronized.
if( std::cin.good() && min <= n && n <= max )
{
return n;
}
}
}

Cheers,

- Alf

--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
Oct 24 '05 #18

P: n/a
* Wolfgang Draxinger:
I always find it interesting in which ways coders react on the
mention of "goto". Yes it is quick and dirty, but IMHO sometimes
pragmatism should be favoured over academical correctnes. And
there are some situations in which a "goto" is the most readable
and clear way to go. A good example would be the initialization
of a device driver (ok, those are normally done in C and not
C++). If something goes wrong there you must make sure that you
revert the state of the device on how you found it.

enum subdevice{A, B, C};

bool init_device()
{
sub_device_status pre_A;
sub_device_status pre_B;
sub_device_status pre_C;

// each init_subdevice_ call initializies the
// internal data structures and then reset the
// subdevice

get_device_status(A, &pre_A);
if( !init_subdevice_A() )
goto failed_A;

get_device_status(B, &pre_B);
if( !init_subdevice_B() )
goto failed_B;

get_device_status(C, &pre_C);
if( !init_subdevice_C() )
goto failed_C;

// All subdevices got initialized properly
return true;

failed_C:
set_device_status(C, pre_C);
failed_B:
set_device_status(B, pre_B);
failed_A:
set_device_status(A, pre_A);

return false;
}

Frankly I don't know a cleaner way to write this, but I'm open to
other suggestions.


class StatusRollback
{
private:
sub_device_status myStatus;
unsigned myDeviceId;
bool iAmCancelled;
public:
StatusRollback( unsigned id ): myDeviceId( id ), iAmCancelled( false )
{
get_device_status( myDeviceId, &myStatus );
}

~StatusRollback()
{
if( !iAmCancelled ) { set_device_status( myDeviceId, &myStatus ); }
}

void cancel() { iAmCancelled = true; }
};

enum SubDeviceId{ deviceA, deviceB, deviceC };

bool InitDevice()
{
StatusRollback rollbackA( deviceA );
if( !init_subdevice_A() ) { return false; }

StatusRollback rollbackB( deviceB );
if( !init_subdevice_B() ) { return false; }

StatusRollback rollbackC( deviceC );
if( !init_subdevice_C() ) { return false; }

rollbackC.cancel();
rollbackB.cancel();
rollbackA.cancel();
return true;
}

It's also more exception safe, although that is presumably not an issue in a
device driver... ;-)

--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
Oct 24 '05 #19

P: n/a
On Tue, 25 Oct 2005 00:05:33 +0200, Wolfgang Draxinger
<wd********@darkstargames.de> wrote:
I always find it interesting in which ways coders react on the
mention of "goto". Yes it is quick and dirty, but IMHO sometimes
pragmatism should be favoured over academical correctnes. And
there are some situations in which a "goto" is the most readable
and clear way to go. A good example would be the initialization
of a device driver (ok, those are normally done in C and not
C++). If something goes wrong there you must make sure that you


"goto" is often frowned upon in C++ because it may transfer control into
another context whose local variables are not properly constructed. It also
encourages "spaghetti code" style programming that is the bane of BASIC
applications.

Most problems that at first appear to need goto's turn out not to need them
once a more complete understanding of the C++ language is applied to the
analysis. However, there are (extremely rare) problems that are best solved
with gotos. Co-routines come to mind.

Escaping from deeply-nested logic statements can sometimes be implemented by
putting the logic in a function and using return to escape, or by enclosing
the block in a do {...} while(false) loop, and using break to escape.

BTW, much to my surprise, a reading of the Standard shows that goto implies
the destruction of auto variables that go out of scope as a result of the
jump. I always thought that goto simply inserted a jump statement in the
object code. I learned something today!

-dr
Oct 25 '05 #20

P: n/a
Thank you all guys!

Oct 25 '05 #21

P: n/a
On 2005-10-24, Alf P. Steinbach <al***@start.no> wrote:
* Kai-Uwe Bux -> Neil Cerutti:

Ahem, what about:

template <typename T>
T ranged_prompt(T min, T max)
{
T n;
do {
std::cout << "Enter a number from " << min << " to " << max ": ";
std::cout.flush()
std::cin >> n;
while (!std::cin || n < min || n > max) {
std::cin.clear();
std::cin.ignore(std::numeric_limits<int>::max(), '\n');
return n;
}
One crucial thing here is the name change, to reflect what the
function produces. I don't think I could guess from the name
'ranged_prompt' (the OP's choice) that it actually does input.
I'd guess it produced a prompt.


Agreed on the function name. I changed it from "f" at the last
minute, and didn't think about it very much.

Possibly "get_ranged_input"? A better version would receive an
istream& instead of hardcoding std::cin, as well.
Of course for good measure -- less Undefined Behavior, those
iostreams aren't my favorite beasts!
Ah, yes. I forgot to check for eof. No sense clearing the stream
if std::cin.eof(). This reveals that the function signature is
probably broken, since I've only left myself the option of
throwing an exception in that case.
-- one should read in a
whole line using getline, and parse it using strtol or strtod
as appropriate (not a stringstream)...


Unfortunately, strtol or strtod are unsuitable except in some
specialization, since we don't know the type of T. The function
should conceivably work with any type supporting <, > and streams.

Here's a new version that's hopefully improved.

/* Leaves junk in result if is.eof() */
template <typename T>
std::istream& get_ranged_input_with_prompt(std::istream& os
, std::istream& is, T& result, const T& min, const T& max)
{
prompt:
os << "Enter a value from " << min << " to " << " max: ";
os.flush();
is >> result;
if (!is && !is.eof()) {
if (result < min || result > max) {
is.clear();
is.ignore(std::numeric_limits<int>::max(), '\n');
goto prompt;
}
}
return is;
}

Hmmm.

--
Neil Cerutti
Oct 25 '05 #22

P: n/a
Tatu Portin wrote:
mlimber wrote:
Tatu Portin wrote:
vineoff wrote:

If I'm having nested loops like:

for (...) for (..) for (...) { /* exit here */ }

and I need to exit from there ^ .

Is it better to use exceptions or goto or some other method?
goto.


I find it clearer to have a variable to indicate that it is time to
exit:

bool done = false;
for( int i=0; !done && i < 10; ++i )
{
for( int j=0; !done && j < 10; ++j )
{
for( int k=0; !done && k < 10; ++k )
{
if( k == 5 ) // Some dummy exit condition
{
done = true;
continue; // or break;
}
}
}
}

In general, you should not use exceptions unless the condition is,
well, exceptional. IOW, don't use exceptions as an alternative to break
and continue when there is not actually an error (however that is
defined).

It is not efficient.

In this situation, you seem to be iterating once over three coordinates.
Has anyone here ever tried defining an object to perform the
iteration? There are several ways to do it, but one might involve
ultimately writing it like so:

for (multi_iterator<int, int, int> i(10, 10, 10); i; ++i) {
// each of the three values of i are used.
break; // Exits the loop.
}

In such a case, the iterator would know its bounds. Iteration would
handle rollover, and evaluating it as a bool would tell whether it was
still within its bounds. If you wrap a tuple, you get all sorts of
simple accessors and extendability for free.
Oct 25 '05 #23

P: n/a

Alf P. Steinbach wrote:
A Do-It-Yourself RAII-based version might go like this:
Very nice solution :)
StreamCleanup cleaner( std::cin );


Warning (line N): Unused variable 'cleaner' ...

;)

How do you work around that warning (without introducing some silly
cleaner.noop(); )?
I encounter exactly that problem in my code every once in a while.

Cheers,
Andre

Oct 25 '05 #24

P: n/a
* Andre (in*****@gmail.com):
* Alf P. Steinbach:

A Do-It-Yourself RAII-based version might go like this:


Very nice solution :)
StreamCleanup cleaner( std::cin );


Warning (line N): Unused variable 'cleaner' ...

;)

How do you work around that warning (without introducing some silly
cleaner.noop(); )?


Warnings are compiler-specific, and most workarounds for them also.

I guess a macro would be thing here, e.g., for g++, off the cuff (might not
work)

#ifdef __GNUG__
#define UNUSED( x ) x __attribute__((unused))
#else
#define UNUSED( x ) x
#endif

#define UNIQUE_NAME //something, using __LINE__ (use __COUNTER__ for MSVC)

#define GUARD( t, args ) t UNUSED( UNIQUE_NAME ) = t args;

...
GUARD( StreamCleanup, (std::cin) );

Or, you can use the compiler option to suppress this particular warning
(again, that depends on the compiler).

Btw., the macro above relies on "()" being valid as a macro argument for the
case of a constructor with no arguments. I don't know whether it really is.
But it's always worked, and the proof is in the pudding, as they say.

--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
Oct 25 '05 #25

P: n/a

Tatu Portin wrote:
mlimber wrote:
Tatu Portin wrote:
vineoff wrote:

If I'm having nested loops like:

for (...) for (..) for (...) { /* exit here */ }

and I need to exit from there ^ .

Is it better to use exceptions or goto or some other method?

goto.

I find it clearer to have a variable to indicate that it is time to
exit:

bool done = false;
for( int i=0; !done && i < 10; ++i )
{
for( int j=0; !done && j < 10; ++j )
{
for( int k=0; !done && k < 10; ++k )
{
if( k == 5 ) // Some dummy exit condition
{
done = true;
continue; // or break;
}
}
}
}

In general, you should not use exceptions unless the condition is,
well, exceptional. IOW, don't use exceptions as an alternative to break
and continue when there is not actually an error (however that is
defined).


It is not efficient.


Did you profile it? Programmers are terrible at judging what is
inefficient and what the compiler can optimize away. Readability and
maintainability, not efficiency, should be the primary concern until a
profiler determines that a certain part of the code should be reworked
for efficiency. Premature optimization is the root of all kinds of
evil, after all. As Herb Sutter said:

"By and large, programmers--that includes you and me--are notoriously
bad at guessing the actual space/time performance bottlenecks in their
own code. If you don't have performance profiles or other empirical
evidence to guide you, you can easily spend days optimizing something
that doesn't need optimizing and that won't measurably affect runtime
space or time performance. What's even worse, however, is that when you
don't understand *what* needs optimizing you may actually end up
pessimizing (degrading your program) by of saving a small cost while
unintentionally incurring a large cost. Once you've run performance
profiles and other tests, and you actually know that a particular
optimization will help you in your particular situation, then it's the
right time to optimize." (http://www.gotw.ca/publications/mill09.htm)

Cheers! --M

Oct 25 '05 #26

P: n/a
"vineoff" <vi*****@gmail.com> wrote in message
news:11*********************@g47g2000cwa.googlegro ups.com...
If I'm having nested loops like:

for (...) for (..) for (...) { /* exit here */ }

and I need to exit from there ^ .

Is it better to use exceptions or goto or some other method?


How about an extra boolean added to each condition:

bool done = false;

for (int i = 0; !done && (i != 3); ++i)
{
for (int j = 0; !done && (j != 3); ++j)
{
// ... etc.

done = /* some exit condition */;
}
}

Ali

Oct 25 '05 #27

P: n/a
"Wolfgang Draxinger" <wd********@darkstargames.de> wrote in message
news:de************@darkstargames.dnsalias.net...
There are some situations in which a "goto" is the most readable
and clear way to go. A good example would be the initialization
of a device driver (ok, those are normally done in C and not
C++). If something goes wrong there you must make sure that you
revert the state of the device on how you found it.

enum subdevice{A, B, C};

bool init_device()
{
sub_device_status pre_A;
sub_device_status pre_B;
sub_device_status pre_C;

// each init_subdevice_ call initializies the
// internal data structures and then reset the
// subdevice

get_device_status(A, &pre_A);
if( !init_subdevice_A() )
goto failed_A;

get_device_status(B, &pre_B);
if( !init_subdevice_B() )
goto failed_B;

get_device_status(C, &pre_C);
if( !init_subdevice_C() )
goto failed_C;

// All subdevices got initialized properly
return true;

failed_C:
set_device_status(C, pre_C);
failed_B:
set_device_status(B, pre_B);
failed_A:
set_device_status(A, pre_A);

return false;
}

Frankly I don't know a cleaner way to write this, but I'm open to
other suggestions.


get_device_status(A, &pre_A);
if( init_subdevice_A() ) {

get_device_status(B, &pre_B);
if( init_subdevice_B() ) {

get_device_status(C, &pre_C);
if( init_subdevice_C() ) {

// All subdevices got initialized properly
return true;

}
set_device_status(C, pre_C);
}
set_device_status(B, pre_B);
}
set_device_status(A, pre_A);

return false;
Oct 26 '05 #28

P: n/a
"red floyd" <no*****@here.dude> wrote in message
news:w8*****************@newssvr27.news.prodigy.ne t...
1. For bailing out of deeply nested loops, GOTO is not necessarily
harmful. But I don't have my copy of the Standard available, and am not
sure if a goto calls destructors when exiting blocks.


Destruction is only one side of the coin. How about construction:

for (;;)
{
goto future;
}

Foo foo;

future:

cout << "doomed\n";

Unfortunately foo will not be constructed in the future.

To the OP: goto is harmful. There is plenty of writing about that, which can
be easily found on the Net.

Ali

Oct 27 '05 #29

P: n/a
"Neil Cerutti" <le*******@email.com> wrote in message
news:sl**********************@FIAD06.norwich.edu.. .
On 2005-10-24, Kai-Uwe Bux <jk********@gmx.net> wrote:
Josh Mcfarlane wrote:
Gotos are horribly outdated IMO. The last place I remember
using them was in QBASIC and the BASIC compilers on Apple IIs
You are entitled to your opinion. However, sometimes
oldfashioned can be the best tool to do a job.


Prompting and verifying input is a case where goto turns out to
seem nice and clean.


Using goto is not nice nor clean. goto is inherently risky and the code
below is obfuscated.

[...]
template <typename T>
T ranged_prompt(T min, T max)
{
T n;
prompt:
std::cout << "Enter a number from " << min << " to " << max ": ";
std::cout.flush()
Aside: flush is unnecessary above. Inputting from cin will cause that anyway
because cin is "tied" to cout (see std::tie).
std::cin >> n;
if (!std::cin || n < min || n > max) {
std::cin.clear();
std::cin.ignore(std::numeric_limits<int>::max(), '\n');
goto prompt;
}
return n;
}


What you do above is "while the input is not good, [...]." What other method
can be more clear than

bool good_input = false;

while ( ! good_input)
{
/* ... */
}

Ali

Oct 27 '05 #30

P: n/a
Ali «ehreli wrote:
"red floyd" <no*****@here.dude> wrote in message
news:w8*****************@newssvr27.news.prodigy.ne t...
1. For bailing out of deeply nested loops, GOTO is not necessarily
harmful. But I don't have my copy of the Standard available, and am
not sure if a goto calls destructors when exiting blocks.

Destruction is only one side of the coin. How about construction:

for (;;)
{
goto future;
}

Foo foo;

future:

cout << "doomed\n";

Unfortunately foo will not be constructed in the future.

To the OP: goto is harmful. There is plenty of writing about that, which
can be easily found on the Net.

Sure, but for the purpose of *BAILING OUT OF A DEEPLY NESTED LOOP*

for (...)
{
for (...)
{
for (...)
{
...
if (disaster)
goto bailout;
}
}
}
bailout:

Note that what you propose can occur *WITHOUT* goto, as well:

switch (expr)
{
case 1:
Foo foo;
case 2:
// uh oh, if expr == 2, foo is not constructed!
foo.bar();
break;
default:
break;
}

Oct 27 '05 #31

P: n/a
<al*******@gmail.com> wrote in message
news:11**********************@f14g2000cwb.googlegr oups.com...
use break


What are you talking about? Use break when? Where? In what context?

Please quote enough of the previous post to make what you say clear.
[Off-topic rant: Google may be hosting the newsgroups today; but that
doesn't mean that they understand the concept.]

If you suggested to "use break" to exit out of multiple loops; that is plain
wrong.

On the other hand, if you suggested to "use break" to take square root of a
double, that is ridiculous...

Ali

Oct 27 '05 #32

P: n/a
* =?iso-8859-1?Q?Ali_=C7ehreli?=:
"red floyd" <no*****@here.dude> wrote in message
news:w8*****************@newssvr27.news.prodigy.ne t...
1. For bailing out of deeply nested loops, GOTO is not necessarily
harmful. But I don't have my copy of the Standard available, and am not
sure if a goto calls destructors when exiting blocks.
Destruction is only one side of the coin. How about construction:

for (;;)
{
goto future;
}

Foo foo;

future:

cout << "doomed\n";

Unfortunately foo will not be constructed in the future.


Happily C++ protects against that: that particular goto is not allowed,
para 6.7/3.

To the OP: goto is harmful. There is plenty of writing about that, which can
be easily found on the Net.


Yep.

--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
Oct 27 '05 #33

P: n/a
On 2005-10-27, Ali «ehreli <ac******@yahoo.com> wrote:
"Neil Cerutti" <le*******@email.com> wrote in message
news:sl**********************@FIAD06.norwich.edu.. .
Prompting and verifying input is a case where goto turns out to
seem nice and clean.


Using goto is not nice nor clean. goto is inherently risky and
the code below is obfuscated.


It ended up a buggy mess. And thus, I refuted myself.

--
Neil Cerutti
Oct 27 '05 #34

P: n/a
TIT
Ali «ehreli sade:
"red floyd" <no*****@here.dude> wrote in message
news:w8*****************@newssvr27.news.prodigy.ne t...
1. For bailing out of deeply nested loops, GOTO is not necessarily
harmful. But I don't have my copy of the Standard available, and am
not sure if a goto calls destructors when exiting blocks.


It does call destructors.

Destruction is only one side of the coin. How about construction:

for (;;)
{
goto future;
}

Foo foo;

If Foo is a POD then this is legal, it will exist and
work properly. (6.7/3)
future:

cout << "doomed\n";

Unfortunately foo will not be constructed in the future.

In any other case this jump is according to the standard
ill-formed, as such not well-formed and therefore undefined
behavior.
To the OP: goto is harmful. There is plenty of writing about that, which
can be easily found on the Net.


Gotos are sometimes quite practical.

TIT

Oct 27 '05 #35

P: n/a
"red floyd" <no*****@here.dude> wrote in message
news:7x*******************@newssvr14.news.prodigy. com...
Ali «ehreli wrote:
"red floyd" <no*****@here.dude> wrote in message
news:w8*****************@newssvr27.news.prodigy.ne t...
1. For bailing out of deeply nested loops, GOTO is not necessarily
harmful. But I don't have my copy of the Standard available, and am not
sure if a goto calls destructors when exiting blocks.

Destruction is only one side of the coin. How about construction:

for (;;)
{
goto future;
}

Foo foo;

future:

cout << "doomed\n";

Unfortunately foo will not be constructed in the future.

To the OP: goto is harmful. There is plenty of writing about that, which
can be easily found on the Net.

Sure, but for the purpose of *BAILING OUT OF A DEEPLY NESTED LOOP*

for (...)
{
for (...)
{
for (...)
{
...
if (disaster)
goto bailout;
}
}
}
bailout:


What if someone adds an object before bailout label later in development.
That object is not constructed because of the goto call.
Note that what you propose can occur *WITHOUT* goto, as well:
That's because switch/case is some type of lookup and a number of gotos in
disguise. Also, maybe less than goto, but switch/case is frowned upon in C++
as well...
switch (expr)
{
case 1:
Foo foo;
case 2:
// uh oh, if expr == 2, foo is not constructed!
foo.bar();
break;
default:
break;
}


Ali

Oct 27 '05 #36

P: n/a
On 2005-10-27, Ali «ehreli <ac******@yahoo.com> wrote:
"red floyd" <no*****@here.dude> wrote in message
news:7x*******************@newssvr14.news.prodigy. com...
Note that what you propose can occur *WITHOUT* goto, as well:


That's because switch/case is some type of lookup and a number
of gotos in disguise. Also, maybe less than goto, but
switch/case is frowned upon in C++ as well...
switch (expr)
{
case 1:
Foo foo;
case 2:
// uh oh, if expr == 2, foo is not constructed!
foo.bar();
break;
default:
break;
}


Yep. If your pesky coding standard forbids goto, switch is a
wonderful simulator. (This is based on something similar I saw at
URL:http://thedailywtf.com/ )

for (int x = 1; x < 8192; ++x) {
switch (x) {
case 10:
std::cout << "Neil Cerutti!!!!!!!\n";
break;
case 20:
x = 10;
break;
}
}

This is known as the Commodore 64 BASIC design pattern.

--
Neil Cerutti
Oct 27 '05 #37

P: n/a
Ali «ehreli wrote:
Destruction is only one side of the coin. How about construction:

for (;;)
{
goto future;
}

Foo foo;

future:

cout << "doomed\n";

Unfortunately foo will not be constructed in the future.

The above program isn't well-formed. The compiler will not let
you transfer control past the initializer.
Oct 27 '05 #38

P: n/a
red floyd wrote:
Sure, but for the purpose of *BAILING OUT OF A DEEPLY NESTED LOOP*

for (...)
{
for (...)
{
for (...)
{
...
if (disaster)
goto bailout;
}
}
}
bailout:


The better solution is to not write deeply nested loops.

--
Salu2
Oct 27 '05 #39

P: n/a
"Mogens Heller Jensen" <mo****@mookid.dk> wrote in message
news:43***********************@nntp02.dk.telia.net ...

[...]
Goto is not dangerous or evil, it's just easy to use in ways that mess up
your code.
[...]
To me it seems people tend to forget why they should not use goto, and
just refrain from using it because their teachers told them not to.
Those teachers probably got their clues directly or indirectly from papers
that analyzed the subject deeply. Saying "goto is not dangerous or evil,"
without refuting the points of those papers doesn't mean much.
You should always consider the solution which creates clear and
understandable code which is easy to maintain.


Those are some of the reasons why goto should not be used:

- goto is not clear: Going to a specific point in the code doesn't say
anything to the reader. Well structured code and well named objects do.

- goto is hard to maintain: You can't insert new objects in to the code
without scanning the entire function to see whether an evil goto may bypass
your object's initialization.

Ali

Oct 29 '05 #40

This discussion thread is closed

Replies have been disabled for this discussion.