efficient exception handling

T

terminator

I found the following as the ANSI C++ std behavior of the exception
handling mechanism in the documentation of my compiler:

Control reaches the try statement by normal sequential execution. The
guarded section within the try block is executed.
If no exception is thrown during execution of the guarded section, the
catch clauses that follow the try block are not executed. Execution
continues at the statement after the last catch clause following the
try block in which the exception was thrown.
If an exception is thrown during execution of the guarded section or
in any routine the guarded section calls (either directly or
indirectly), an exception object is created from the object created by
the throw operand. (This implies that a copy constructor may be
involved.) At this point, the compiler looks for a catch clause in a
higher execution context that can handle an exception of the type
thrown (or a catch handler that can handle any type of exception). The
catch handlers are examined in order of their appearance following the
try block. If no appropriate handler is found, the next dynamically
enclosing try block is examined. This process continues until the
outermost enclosing try block is examined.
If a matching handler is still not found, or if an exception occurs
while unwinding, but before the handler gets control, the predefined
run-time function terminate is called. If an exception occurs after
throwing the exception, but before the unwind begins, terminate is
called.
If a matching catch handler is found, and it catches by value, its
formal parameter is initialized by copying the exception object. If it
catches by reference, the parameter is initialized to refer to the
exception object. After the formal parameter is initialized, the
process of unwinding the stack begins. This involves the destruction
of all automatic objects that were constructed (but not yet
destructed) between the beginning of the try block associated with the
catch handler and the exception's throw site. Destruction occurs in
reverse order of construction. The catch handler is executed and the
program resumes execution following the last handler (that is, the
first statement or construct which is not a catch handler). Control
can only enter a catch handler through a thrown exception, never via a
goto statement or a case label in a switch statement.

I do not feel much doubt about the standardness of the above context ,
but IMO the std could be more elegant with the some minor
modifications;
i.It looks as if the stack unwinding is performed at 'throw'
site .but IMHO if the stack unwinding is left to the 'catch' site the
program will be more flexible;because it gives us the option to handle
the trouble and resume the program from the statement after the
throw ,rather than stopping what was performing before the
throw.Therefore a default exception handler also need be implicitly
defined ,so that it can catch all exeptions and do nothing but unwind
the stack and terminate.
ii.Appliction of some existing keywords can be extended:

1.default:

The 'default' keyword can be introduced as an acceptable parameter to
the 'throw' statement as the uncatchable(unhandleable) exception which
cannot be cought by any catch block except the implicitly defined
default handler ,so that a 'throw default' performs a secure exit on
current thread:

try{
throw default;/*unwind the stack completely ,then terminate this
thread.*/
}catch(...){
//shall never be reached:cannot catch the default exception.
}


2.break:

A 'break' statement inside a catch block - that does not belong to any
loop or 'switch' statement - must break the catch block:

try{
throw "serious but not fatal";
}catch(...){
A ca;
B cb;
if(condition) break;//goto end;
do_something();
end:
}/* cb.~B(); ca.~A();*/



3.continue:

A 'continue' statement inside a catch block - that does not belong to
any loop - must mean that the exception has been resolved and the
program should resume from the first statement after the 'throw' that
has raised or re-thrown the exception :

try{
throw "throw 1";
keep_on1:
do_something();

}cathch(const char *){
try{
throw;//re-throw
keep_on2:
continue;/*go to keep_on1 as if every thing were ok.*/

}catch(...){
continue;/*go to keep_on2 as if no ecxeption has occured*/
}
}

Thus if a catch block owns a 'continue' statment,the compiler should
postpone stack unwinding to exiting from the catch block - either
normally or via a 'break' or 'goto' to outside the catch block- rather
than the beginning of catch block.

regards,
FM.
 
G

Guest

I found the following as the ANSI C++ std behavior of the exception
handling mechanism in the documentation of my compiler:

Control reaches the try statement by normal sequential execution. The
guarded section within the try block is executed.
If no exception is thrown during execution of the guarded section, the
catch clauses that follow the try block are not executed. Execution
continues at the statement after the last catch clause following the
try block in which the exception was thrown.
If an exception is thrown during execution of the guarded section or
in any routine the guarded section calls (either directly or
indirectly), an exception object is created from the object created by
the throw operand. (This implies that a copy constructor may be
involved.) At this point, the compiler looks for a catch clause in a
higher execution context that can handle an exception of the type
thrown (or a catch handler that can handle any type of exception). The
catch handlers are examined in order of their appearance following the
try block. If no appropriate handler is found, the next dynamically
enclosing try block is examined. This process continues until the
outermost enclosing try block is examined.
If a matching handler is still not found, or if an exception occurs
while unwinding, but before the handler gets control, the predefined
run-time function terminate is called. If an exception occurs after
throwing the exception, but before the unwind begins, terminate is
called.
If a matching catch handler is found, and it catches by value, its
formal parameter is initialized by copying the exception object. If it
catches by reference, the parameter is initialized to refer to the
exception object. After the formal parameter is initialized, the
process of unwinding the stack begins. This involves the destruction
of all automatic objects that were constructed (but not yet
destructed) between the beginning of the try block associated with the
catch handler and the exception's throw site. Destruction occurs in
reverse order of construction. The catch handler is executed and the
program resumes execution following the last handler (that is, the
first statement or construct which is not a catch handler). Control
can only enter a catch handler through a thrown exception, never via a
goto statement or a case label in a switch statement.

I do not feel much doubt about the standardness of the above context ,
but IMO the std could be more elegant with the some minor
modifications;

To my knowledge the way exceptions work in C++ is very similar to the
way they work in other languages (though I do not claim to have
knowledge of all languages that support exceptions). I would assume that
this is not because the inventors of the other languages could not
imagine other ways to do things, but rather because it is the most sane
way of doing things.
i.It looks as if the stack unwinding is performed at 'throw'
site .but IMHO if the stack unwinding is left to the 'catch' site the
program will be more flexible;because it gives us the option to handle
the trouble and resume the program from the statement after the
throw ,rather than stopping what was performing before the
throw.

If it was possible to handle the exception at the site where it was
thrown it should have been caught at the same place and the problem
fixed and no exception would have propagated in the first place. The
reason for an exception to be caught at another site would be because
that is to only logical place to handle the exception.
Therefore a default exception handler also need be implicitly
defined ,so that it can catch all exeptions and do nothing but unwind
the stack and terminate.
ii.Appliction of some existing keywords can be extended:

1.default:

The 'default' keyword can be introduced as an acceptable parameter to
the 'throw' statement as the uncatchable(unhandleable) exception which
cannot be cought by any catch block except the implicitly defined
default handler ,so that a 'throw default' performs a secure exit on
current thread:

try{
throw default;/*unwind the stack completely ,then terminate this
thread.*/
}catch(...){
//shall never be reached:cannot catch the default exception.
}

The whole idea behind exceptions it that they can be thrown and then
caught, why would anyone want an uncatchable exception? If you want to
terminate the program there are other ways to do so, such as abort().
2.break:

A 'break' statement inside a catch block - that does not belong to any
loop or 'switch' statement - must break the catch block:

try{
throw "serious but not fatal";
}catch(...){
A ca;
B cb;
if(condition) break;//goto end;
do_something();
end:
}/* cb.~B(); ca.~A();*/

That would be convenient, but hardly something that we can not live
without, the same thing can be accomplished using both goto (ugh!) and
the normal control statements.
3.continue:

A 'continue' statement inside a catch block - that does not belong to
any loop - must mean that the exception has been resolved and the
program should resume from the first statement after the 'throw' that
has raised or re-thrown the exception :

try{
throw "throw 1";
keep_on1:
do_something();

}cathch(const char *){
try{
throw;//re-throw
keep_on2:
continue;/*go to keep_on1 as if every thing were ok.*/

}catch(...){
continue;/*go to keep_on2 as if no ecxeption has occured*/
}
}

Thus if a catch block owns a 'continue' statment,the compiler should
postpone stack unwinding to exiting from the catch block - either
normally or via a 'break' or 'goto' to outside the catch block- rather
than the beginning of catch block.

Consider the following, an exception is thrown in a constructor. In the
catch-block you use continue to resume the execution which means that
your code will continue to run and try to perform operations on a not
fully constructed object. Not a good idea. The reason the exception was
thrown was that correct execution was no longer possible, the only
correct way of handling this is to go back a little and then deal with
the situation (by aborting, trying again, trying something different, etc.).
 
J

James Kanze

I found the following as the ANSI C++ std behavior of the
exception handling mechanism in the documentation of my
compiler:

[...]
I do not feel much doubt about the standardness of the above
context , but IMO the std could be more elegant with the some
minor modifications;
i.It looks as if the stack unwinding is performed at 'throw'
site .but IMHO if the stack unwinding is left to the 'catch' site the
program will be more flexible;because it gives us the option to handle
the trouble and resume the program from the statement after the
throw, rather than stopping what was performing before the
throw.

This option was discussed by the committee when exceptions were
added to the language, and rejected. Basically, the people with
actual experience with it (in other languages) reported that it
couldn't really be used effectively, and it complicated the
implementation somewhat, so the decision was made to not support
it. (Simply specifying the semantics for this would be
extremely complicated. The catch block runs in a different
scope than that where the exception was raised.)
Therefore a default exception handler also need be implicitly
defined ,so that it can catch all exeptions and do nothing but
unwind the stack and terminate.

IMHO, the current situation is actually better. A compiler is
free to terminate without unwinding the stack (and
some---including the ones I use---do), so you can see where the
uncaught exception came from.
 
J

James Kanze

On 2007-10-15 09:44, terminator wrote:

[...]
To my knowledge the way exceptions work in C++ is very similar to the
way they work in other languages (though I do not claim to have
knowledge of all languages that support exceptions). I would assume that
this is not because the inventors of the other languages could not
imagine other ways to do things, but rather because it is the most sane
way of doing things.

It depends on the time frame, I think. Resumable exceptions was
a frequent feature in languages which implemented them before
C++, I think. The reason C++, and other more recent languages,
don't support it is a result of concrete experience with it in
these other languages.
If it was possible to handle the exception at the site where
it was thrown it should have been caught at the same place and
the problem fixed and no exception would have propagated in
the first place. The reason for an exception to be caught at
another site would be because that is to only logical place to
handle the exception.

If it was possible to handle the error condition at the site
where it was detected, one should do so, and not raise an
exception to begin with.

The usual argument for resumable exceptions is that the catch
block will somehow "correct" the condition which caused the
error, so you can resume. Of course, this doesn't work in
practice, because by the time you catch the exception, you've
generally done some things which would not have been done, or
which would have been done differently in the new context.
 
N

Nick Keighley

On 2007-10-15 09:44, terminator wrote:

The whole idea behind exceptions it that they can be thrown and then
caught, why would anyone want an uncatchable exception? If you want to
terminate the program there are other ways to do so, such as abort().

destructors. You might want to leave things in a "safe" state before
you
terminate the program. Close the working file. Release the database.
Turn off the heat in the cat cracker.
 
A

Alf P. Steinbach

* James Kanze:
I found the following as the ANSI C++ std behavior of the
exception handling mechanism in the documentation of my
compiler:
[...]
I do not feel much doubt about the standardness of the above
context , but IMO the std could be more elegant with the some
minor modifications;
i.It looks as if the stack unwinding is performed at 'throw'
site .but IMHO if the stack unwinding is left to the 'catch' site the
program will be more flexible;because it gives us the option to handle
the trouble and resume the program from the statement after the
throw, rather than stopping what was performing before the
throw.

This option was discussed by the committee when exceptions were
added to the language, and rejected. Basically, the people with
actual experience with it (in other languages) reported that it
couldn't really be used effectively, and it complicated the
implementation somewhat, so the decision was made to not support
it. (Simply specifying the semantics for this would be
extremely complicated. The catch block runs in a different
scope than that where the exception was raised.)
Therefore a default exception handler also need be implicitly
defined ,so that it can catch all exeptions and do nothing but
unwind the stack and terminate.

IMHO, the current situation is actually better. A compiler is
free to terminate without unwinding the stack (and
some---including the ones I use---do), so you can see where the
uncaught exception came from.

Well, there is in interesting middle way, the Eiffel retry. Basically
it's built on the notion that a function (or block, whatever) either
succeeds or fails, where failure is the propagation of an exception. So
you set up a loop, and in catching an exception you can either loop
again (presumably correcting something or just retrying after a delay),
or propagate the exception, e.g. by rethrowing or throwing some new x.

I once suggested implementing the Eiffel scheme by allowing "goto try"
in a catch block, which would then require a "throw;" as the last
statement of that catch block.

However, this can be simulated via the template pattern in C++, e.g.
Dave Harris' suggestion (as I recall in response to the "goto try")

struct Retrier {
void doit( unsigned maxTries );
protected:
virtual void attempt( unsigned tryCount,
const std::string &errorMessage ) = 0;
};

void Retrier::doit( unsigned maxTries ) {
std::string errorMessage;
for (unsigned tryCount = 1; true; ++tryCount)
try {
attempt( tryCount, errorMessage );
return;
}
catch (std::exception &e) {
if (count < maxTries)
errorMessage = e.what();
else
throw;
}
}
}

but that's kludgy and not as generic as one would wish: it's like the
language lacked blocks so that you had to define a function everywhere
you needed a local block (essentially the same problem as with e.g.
for_each, and perhaps C++0x will help in this respect).

And in response to the above idea I later suggested syntax like

succeed_or_throw_block:
succeed_or_throw_clause +
(fallback_clauses | nothing) +
(cleanup_clause | nothing)

succeed_or_throw_clause:
"succeed_or_throw" compound_stmt

fallback_clauses:
fallback_clause | fallback_clauses fallback_clause

fallback_clause:
"fallback_to" (xinfo_object_decl | nothing) compound_stmt

cleanup_clause:
"clean_up" compound_stmt

xinfo_object_decl:
"(" xinfo_class_name xinfo_name ")"

xinfo_class_name:
identifier // Name of class with certain properties.

xinfo_name:
identifier // Variable scoped in following compound_stmt.

succeed_stmt:
"succeed" (return_stmt | ";")

which could conceivably support nested exceptions, a statically selected
number of retries/fallbacks, and would yield cleaner more readable
syntax, but suffers from non-local handling of failure.

In short, there is a very wide range of options for exception handling.

C++'s "try catch" has the virtue of being simple, but doesn't handle
nested exceptions, and makes it awkward to do Eiffel style handling.

Cheers,

- Alf
 
T

terminator

Consider the following, an exception is thrown in a constructor. In the
catch-block you use continue to resume the execution which means that
your code will continue to run and try to perform operations on a not
fully constructed object. Not a good idea. The reason the exception was
thrown was that correct execution was no longer possible, the only
correct way of handling this is to go back a little and then deal with
the situation (by aborting, trying again, trying something different, etc..).

I see : Since throw is usually used as a conditional jump, the next
instruction is executed with the assumption that oposite of the
condition is true where a continue can not fix the affected data.
The solution is easy ,one must avoid a 'continue'd catch block for old
exception classes thrown by hopeless outdated algorithms that do not
consider a second chance .

A 'throw' statement can reflect the source of error instead of just
nagging:

class foo{
public:
foo()throw(foo*){
if(some_problem)
throw this;
};
};

bool fix(foo *);

try{
foo obj;
}catch(foo * what){
if (fix(what))
continue;//(*what) is valid now.
throw;//could not solve it:reporting daddy
}

The up-to-date algorithms can use a loop instead of a simple
conditional statement;So that on resume the condition of loop is
checked again (redo_loop is the statement next to throw ):


void UpToDate_algorithm(){
while(condition())//{
throw UpToDate_exception();
/* redo_loop:
};*/
};

try{
UpToDate_algorithm();
}catch(UpToDate_exception&){
UpToDate_handler();
continue;
}

We can remove the risk of undefined behavoir completely(even for old
libraries), via some minimal changes to syntax:

A try block must be allowed to omit the catch block .The 'throw' shall
unwind the stack up to the first dynamically enclosing 'try' then look
for the handler, if no handler then the default handler cleans the
stack and terminates.The 'continue' shall resume from the beginning of
the inner-most enclosing 'try':

void foo(){
class A in_foo;
foo_try:
try{
A in_foo_try;
if (condition)
throw "guarded throw";/*unwind the try
block:in_foo_try.~A(); do not touch in_foo*/
}
throw "freethrow";/*unwind stack up to bar_try:
in_foo_try.~A() ; in_foo.~A() ;
in_bar_try.~A() ;*/
};

void bar(){
bar_try:
try{
A in_bar_try;
foo();
}catch(...){
if (condition)
continue;//long goto ( free throw ? bar_try : foo_try );
}//unwind the rest of stack occupied by bar_try
}

This way we do not need explicit loops and no more than essential data
is destructed and reconstructed.

regards,
FM.
 
T

terminator

On 2007-10-15 09:44, terminator wrote:
[...]
I do not feel much doubt about the standardness of the above context ,
but IMO the std could be more elegant with the some minor
modifications;
To my knowledge the way exceptions work in C++ is very similar to the
way they work in other languages (though I do not claim to have
knowledge of all languages that support exceptions). I would assume that
this is not because the inventors of the other languages could not
imagine other ways to do things, but rather because it is the most sane
way of doing things.

It depends on the time frame, I think. Resumable exceptions was
a frequent feature in languages which implemented them before
C++, I think. The reason C++, and other more recent languages,
don't support it is a result of concrete experience with it in
these other languages.

Maybe there existed no pratical idea to implement it at that
time .Edison failed to build the lamp thousands of times ,but at least
he learnt a thousant ways of not making lamps.
If it was possible to handle the error condition at the site
where it was detected, one should do so, and not raise an
exception to begin with.

The usual argument for resumable exceptions is that the catch
block will somehow "correct" the condition which caused the
error, so you can resume. Of course, this doesn't work in
practice, because by the time you catch the exception, you've
generally done some things which would not have been done, or
which would have been done differently in the new context.

what is context? can u describe more plz?
Is it another thread or a different stack segment or OS access level
or another computer or what?

thanks,
FM.
 
B

Bo Persson

terminator wrote:
::
:: Consider the following, an exception is thrown in a constructor.
:: In the catch-block you use continue to resume the execution which
:: means that
:: your code will continue to run and try to perform operations on a
:: not
:: fully constructed object. Not a good idea. The reason the
:: exception was thrown was that correct execution was no longer
:: possible, the only
:: correct way of handling this is to go back a little and then deal
:: with
:: the situation (by aborting, trying again, trying something
:: different, etc.).
::
:
: I see : Since throw is usually used as a conditional jump, the next
: instruction is executed with the assumption that oposite of the
: condition is true where a continue can not fix the affected data.
: The solution is easy ,one must avoid a 'continue'd catch block for
: old exception classes thrown by hopeless outdated algorithms that
: do not consider a second chance .
:
: A 'throw' statement can reflect the source of error instead of just
: nagging:
:
: class foo{
: public:
: foo()throw(foo*){
: if(some_problem)
: throw this;
: };
: };

If the constructor throws, there will be no foo object. The this
pointer has nothing to point to!

:
: bool fix(foo *);
:
: try{
: foo obj;
: }catch(foo * what){
: if (fix(what))
: continue;//(*what) is valid now.
: throw;//could not solve it:reporting daddy
: }

If you know how to fix the problem for foo, why not just pass it the
fix function in its constructor, and let if fix itself up?


Bo Persson
 
J

James Kanze

On 2007-10-15 09:44, terminator wrote:
[...]
I do not feel much doubt about the standardness of the above context ,
but IMO the std could be more elegant with the some minor
modifications;
To my knowledge the way exceptions work in C++ is very similar to the
way they work in other languages (though I do not claim to have
knowledge of all languages that support exceptions). I would assume that
this is not because the inventors of the other languages could not
imagine other ways to do things, but rather because it is the most sane
way of doing things.
It depends on the time frame, I think. Resumable exceptions was
a frequent feature in languages which implemented them before
C++, I think. The reason C++, and other more recent languages,
don't support it is a result of concrete experience with it in
these other languages.
Maybe there existed no pratical idea to implement it at that
time .Edison failed to build the lamp thousands of times ,but at least
he learnt a thousant ways of not making lamps.

It wasn't a problem of implementing it. The problem was mainly
deciding what it would do, and to make that something useful.
Actual experience at the time indicated that resumable
exceptions weren't useful.
what is context? can u describe more plz?
Is it another thread or a different stack segment or OS access level
or another computer or what?

No. The problem is that when you detect the error, you have to
correct something for resuming to make sense; otherwise, you
just continue with the same error. And that something is
something that occured in a context before the error was
detected. So you have to resume somewhere before the throw
statement (where---no one knows), undoing anything that had been
done between the point of resumption and the throw.
 
T

terminator

terminator wrote:

::
:: Consider the following, an exception is thrown in a constructor.
:: In the catch-block you use continue to resume the execution which
:: means that
:: your code will continue to run and try to perform operations on a
:: not
:: fully constructed object. Not a good idea. The reason the
:: exception was thrown was that correct execution was no longer
:: possible, the only
:: correct way of handling this is to go back a little and then deal
:: with
:: the situation (by aborting, trying again, trying something
:: different, etc.).
::
:
: I see : Since throw is usually used as a conditional jump, the next
: instruction is executed with the assumption that oposite of the
: condition is true where a continue can not fix the affected data.
: The solution is easy ,one must avoid a 'continue'd catch block for
: old exception classes thrown by hopeless outdated algorithms that
: do not consider a second chance .
:
: A 'throw' statement can reflect the source of error instead of just
: nagging:
:
: class foo{
: public:
: foo()throw(foo*){
: if(some_problem)
: throw this;
: };
: };

If the constructor throws, there will be no foo object. The this
pointer has nothing to point to!

If you view the post carfully ,you`ll find that On Oct 15, 10:44 am,
I said:
It looks as if the stack unwinding is performed at 'throw'
site .but IMHO if the stack unwinding is left to the 'catch' site the
program will be more flexible;because it gives us the option to handle
the trouble and resume the program from the statement after the
throw ,rather than stopping what was performing before the
throw.Therefore a default exception handler also need be implicitly
defined ,so that it can catch all exeptions and do nothing but unwind
the stack and terminate.
:
: bool fix(foo *);
:
: try{
: foo obj;
: }catch(foo * what){
: if (fix(what))
: continue;//(*what) is valid now.
: throw;//could not solve it:reporting daddy
: }

If you know how to fix the problem for foo, why not just pass it the
fix function in its constructor, and let if fix itself up?

The point is that I might not know that when writing the class or I
may be not certain which of several options is best to do and leave
the decission to utilization time.

regards,
FM.
 
T

terminator

No. The problem is that when you detect the error, you have to
correct something for resuming to make sense; otherwise, you
just continue with the same error. And that something is
something that occured in a context before the error was
detected. So you have to resume somewhere before the throw
statement (where---no one knows), undoing anything that had been
done between the point of resumption and the throw.

here is my answer to a similar disagreement from MR Wilson:

Consider the following, an exception is thrown in a constructor. In the
catch-block you use continue to resume the execution which means that
your code will continue to run and try to perform operations on a not
fully constructed object. Not a good idea. The reason the exception was
thrown was that correct execution was no longer possible, the only
correct way of handling this is to go back a little and then deal with
the situation (by aborting, trying again, trying something different, etc..).

I see : Since throw is usually used as a conditional jump, the next
instruction is executed with the assumption that oposite of the
condition is true where a continue can not fix the affected data.
The solution is easy ,one must avoid a 'continue'd catch block for
old
exception classes thrown by hopeless outdated algorithms that do not
consider a second chance .

A 'throw' statement can reflect the source of error instead of just
nagging:


class foo{
public:
foo()throw(foo*){
if(some_problem)
throw this;
};



};


bool fix(foo *);

try{
foo obj;


}catch(foo * what){


if (fix(what))
continue;//(*what) is valid now.
throw;//could not solve it:reporting daddy


}


The up-to-date algorithms can use a loop instead of a simple
conditional statement;So that on resume the condition of loop is
checked again (redo_loop is the statement next to throw ):

void UpToDate_algorithm(){
while(condition())//{
throw UpToDate_exception();
/* redo_loop:
};*/



};


try{
UpToDate_algorithm();

}catch(UpToDate_exception&){


UpToDate_handler();
continue;


}


We can remove the risk of undefined behavoir completely(even for old
libraries), via some minimal changes to syntax:

A try block must be allowed to omit the catch block .The 'throw'
shall
unwind the stack up to the first dynamically enclosing 'try' then
look
for the handler, if no handler then the default handler cleans the
stack and terminates.The 'continue' shall resume from the beginning
of
the inner-most enclosing 'try':


void foo(){
class A in_foo;
foo_try:
try{
A in_foo_try;
if (condition)
throw "guarded throw";/*unwind the try
block:in_foo_try.~A(); do not touch in_foo*/
}
throw "freethrow";/*unwind stack up to bar_try:
in_foo_try.~A() ; in_foo.~A() ;
in_bar_try.~A() ;*/



};


void bar(){
bar_try:
try{
A in_bar_try;
foo();
}catch(...){
if (condition)
continue;//long goto ( free throw ? bar_try : foo_try );
}//unwind the rest of stack occupied by bar_try


}


This way we do not need explicit loops and no more than essential
data
is destructed and reconstructed.

regards,
FM.
 
G

Guest

If you view the post carfully ,you`ll find that On Oct 15, 10:44 am,
I wrote:

[snip previous posted text]

I have not found the relevant sections of the standard, but TC++PL says
that an object is not considered created until its constructor is done.
What that means is that even if you do not unwind the stack there is no
object if the constructor throws.
 
B

BobR

terminator wrote in message...
/* """
I see : Since throw is usually used as a conditional jump, the next
instruction is executed with the assumption that oposite of the
condition is true where a continue can not fix the affected data.
The solution is easy ,one must avoid a 'continue'd catch block for old
exception classes thrown by hopeless outdated algorithms that do not
consider a second chance .
""" */

You seem to want exceptions to control program flow. That doesn't seem
logical to me. (maybe in a toy-program for experimentation it's ok).

Say you are flying an aircraft, and you have a parachute. The aircraft is
your program, the parachute is your exception. Now the engine cuts out. You
can try to glide the aircraft into a safe landing, or bail out. What you
seem to want is to somehow get out of the parachute and back into the
aircraft (which by now has crashed!). It is NOT a good idea!
You can stay with the aircraft and try to save it. If you fail that, hit the
silk, and try to stear your parachute to a safe landing (the catch
clause(s)).

Re-throw? That's your spare parachute (you still can't get back in the
aircraft from there and expect to fly it!).

If you can test something in your program, correct it and continue, you
don't need exceptions, IMHO. Exceptions are for when your program is too far
gone to save, it just gives you a chance to clean-up/inform_users before the
end happens.

In a case like a function-level try block in a constructor, you can not even
fully handle the exception. The object does not exist, the exception is
passed back out to the next catch level (and if that does not exist, the
program is terminated.).
[ 'passed back out' includes re-throw, throw something else, etc. ]

There are always exceptions to when/where to use exceptions. Program flow
control ain't one of them I consider. :-}

Just my two-pico cents on it. <G>
[ rebuttals, corrections welcome. ]
 

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

Forum statistics

Threads
473,766
Messages
2,569,569
Members
45,043
Latest member
CannalabsCBDReview

Latest Threads

Top