|
|
|
#1 |
|
Messages: n/a
Hébergeur: |
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. |
|
|
|
#2 |
|
Messages: n/a
Hébergeur: |
On 2007-10-15 09:44, terminator wrote:
> 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.). -- Erik Wikström |
|
|
|
#3 |
|
Messages: n/a
Hébergeur: |
On Oct 15, 9:44 am, terminator <farid.mehr...@gmail.com> wrote:
> 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. -- James Kanze (GABI Software) email:james.kanze@gmail.com Conseils en informatique orientée objet/ Beratung in objektorientierter Datenverarbeitung 9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34 |
|
|
|
#4 |
|
Messages: n/a
Hébergeur: |
On Oct 15, 12:17 pm, Erik Wikström <Erik-wikst...@telia.com> wrote:
> 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. > > 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. 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. -- James Kanze (GABI Software) email:james.kanze@gmail.com Conseils en informatique orientée objet/ Beratung in objektorientierter Datenverarbeitung 9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34 |
|
|
|
#5 |
|
Messages: n/a
Hébergeur: |
On 15 Oct, 11:17, Erik Wikström <Erik-wikst...@telia.com> wrote:
> On 2007-10-15 09:44, terminator wrote: <snip> > > 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: <snip> > 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. -- Nick Keighley |
|
|
|
#6 |
|
Messages: n/a
Hébergeur: |
* James Kanze:
> On Oct 15, 9:44 am, terminator <farid.mehr...@gmail.com> wrote: >> 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 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 -- 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? |
|
|
|
#7 |
|
Messages: n/a
Hébergeur: |
On Oct 15, 1:17 pm, Erik Wikström <Erik-wikst...@telia.com> 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; }; }; 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. |
|
|
|
#8 |
|
Messages: n/a
Hébergeur: |
On Oct 15, 2:44 pm, James Kanze <james.ka...@gmail.com> wrote:
> On Oct 15, 12:17 pm, Erik Wikström <Erik-wikst...@telia.com> wrote: > > > 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. > > > > 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. > > 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. |
|
![]() |
| Outils de la discussion | |
|
|