morrison@eecs.nwu.edu (Vance Morrison) (03/29/88)
A PROPOSAL FOR ADDING EXCEPTION HANDLING TO C++ I have heard that exception handling for C++ is "in the thinking about stage". Unfortunately, not having exceptions is severely camping my style and so I am writing a preprocessor that adds exception handling to C++. It would be VERY nice if the exception handling scheme that I implement be very similar to the type eventually implemented in the language (when that happens). Thus I would like to submit my proposal to the net to see what everyone thinks. This proposal is at present very informal. After the first round of discussion, we may want to formalize it. STRATEGY: C and C++ derive their strength from the fact that the language itself is small. Instead, most of the power in C and C++ comes from library routines. This give the programmer much more flexibility in extending the language and also simplifies porting the language. Thus I propose changing the language as little as necessary to support exceptions. EXCEPTIONS: Exceptions allow the programmer to bypass the normal flow of control of the program. By raising an exception, a procedure can signal an abnormal condition that the procedure is not prepared to handle. Raising an exception thus initiates a search up the call stack for a routine that can "handle" the exception. If an exception handler is found, control is handed to it. If no handler is found, a "last chance" handler is executed which usually prints out an error message, produces a stack trace and aborts the program. I will not go into the merits of exceptions, but I will state that they are indispensable for reusable modules because they give default error handling to the module designer, while allowing the module user to change error handling. PROPOSAL: Only three changes to the syntax of the language are necessary 1) Add the statement '_raise' to the language: 1) Add the statement 'resume' to the language: 2) Any statement can now be followed by the following construct catch <statement> For example i = j/k; catch { printf("divide by zero error\n"); } As one might expect, '_raise' raises an exception, while 'catch' declares a handler for a statement. Thus whatever statement precedes 'catch' is "protected", in the sense that if any exception is raised in the protected statement, control is given to the statement after 'catch'. For example err() { if (<error condition>) _raise; } main() { err(); catch { printf("error"); } printf("done\n") } In this example the statement 'err();' is protected, so that if an exception is raised in 'err();' then "error" is printed. After the statement after 'catch' is executed, _raise IS IMPLICITLY CALLED. Thus in the above example after "error" is printed _raise is implicitly called and the last chance handler is called. Thus "done" is NEVER printed out. To provide the facility to return to normal flow of control the 'resume' statement is use. For example main() { err(); catch { printf("error"); resume; } printf("done\n") } Now if an exception is raised in 'err()' then "error" will be printed and control will be resume at 'printf("done");'. This behavior is deliberate. The reasoning is that error conditions should NEVER be ignored by default. Thus if the error is to be ignored (that is normal flow of control is to resume), the programmer must explicitly say so by using the resume statement. SYNTACTIC AMBIGUITIES In the following example for(i=0; i< 10; i++) { printf("%d\n", err()); } catch { printf("error\n"); resume; } Is the 'catch' statement only protecting the printf, or the whole for(;;) statement? Here we define it to be just the printf statement. If the other meaning was desired, the syntax would be { for(i=0; i< 10; i++) { printf("%d\n", err()); } } catch { printf("error\n"); resume; } FUNCTION BODIES A function body is a legal statement to catch thus int main() { err(); return(0); } catch { printf("err\n"); return(-1); } Is legal and protects the whole function body. Note that 'return' is a legal statement in a catch clause, and is another way to escape from a catch clause (goto will also work). MAKING IT USEFUL The changes to the language were designed to be minimal. In this raw form it is not very useful since only one unnamed exception can be raised. But using just this simple basis, I have designed a module that implements named exceptions with parameters in C++. Below is an example of a module with three exceptions FILE_N_FOUND, FILE_NUMBERS, and FILE_ERROR. In the main program the function 'file_call' is protected so that if FILE_ERROR or FILE_N_FOUND is raised, they are caught and their parameters examined. All other exceptions will be reraised and the last chance handler will be invoked. I will not explain the workings of my exception module here. This example is only meant to show that a sophisticated exception module can be built from the simple tools I propose. SO WHAT DO YOU THINK???? Vance Morrison morrison@accuvax.nwu.edu morrison@nuacc.bitnet ****** GENERIC MODULE HEADER FILE ********************************* extern void file_call(); /* declare FILE_N_FOUND with a parameter 'name' of type 'char_ptr' */ DECLARE_EXCEPTION_1(FILE_N_FOUND, char_ptr, name); /* declare FILE_N_FOUND with a parameter 'name' of type 'char_ptr' and a parameter 'number' of type 'int' */ DECLARE_EXCEPTION_2(FILE_NUMBERS, char_ptr, name, int, number); /* declare FILE_N_FOUND with no parameters */ DECLARE_EXCEPTION_0(FILE_ERROR); ****** GENERIC MODULE ********************************************* #include "exception.h" #include "example.h" /* the string given here will be printed out using "printf" and the parameters (in order) by the default handler */ CREATE_EXCEPTION(FILE_N_FOUND, "File name '%s' not found"); CREATE_EXCEPTION(FILE_ERROR, "Generic file error"); CREATE_EXCEPTION(FILE_NUMBERS, "File name '%s' has error at number '%d'\n"); void file_call() { FILE_NUMBERS.raise("myfile", 10); } ****** PROGRAM USING MODULE **************************************** #include <stdio.h> #include "exception.h" #include "example.h" main() { /* call file_call and catch the FILE_ERROR FILE_NUMBERS */ file_call(); catch { if (FILE_ERROR.is_raised()) { printf("caught file error\n"); resume; } if (FILE_NUMBERS.is_raised()) { printf("caught file number error with param %d\n", FILE_NUMBERS.number()); resume; } } printf("done\n"); }
dhesi@bsu-cs.UUCP (Rahul Dhesi) (03/30/88)
In article <8180006@eecs.nwu.edu> morrison@eecs.nwu.edu (Vance Morrison) writes: >A PROPOSAL FOR ADDING EXCEPTION HANDLING TO C++ ... >Thus if the error >is to be ignored (that is normal flow of control is to resume), the >programmer must explicitly say so by using the resume statement. The Ada designers chose not to allow execution of a block to continue after an exception occurred. The original Rationale actually gives an example of how to achieve this effect nevertheless: by invoking a procedure again if an exception occurs the first time. The reason for not allowing a "resume" or equivalent was (I guess) to avoid undue complexity in programs. Many exceptions can occur at unpredictable times (e.g. numeric overflow/underflow at any point during expression evaluation, I/O error in the middle of a block of data being written or read), and allowing resumption of the interrupted statement could be awfully risky. On the face of it, it also seems to make life more complicated for the compiler writer to allow a "resume" statement. This is something worth keeping in mind. -- Rahul Dhesi UUCP: <backbones>!{iuvax,pur-ee,uunet}!bsu-cs!dhesi
lgy@pupthy2.PRINCETON.EDU (Larry Yaffe) (03/30/88)
In article <8180006@eecs.nwu.edu> morrison@eecs.nwu.edu (Vance Morrison) writes: >A PROPOSAL FOR ADDING EXCEPTION HANDLING TO C++ [fairly reasonable proposal deleted] > SO WHAT DO YOU THINK???? > > Vance Morrison > morrison@accuvax.nwu.edu > morrison@nuacc.bitnet As far as I can tell, this proposal for exception handling (as well as exception handling in many other languages) fails to allow a very basic form of exception handling that I regard as essential: the ability for an exception handler to return control to the point at which the exception was (first) raised and NOT disturb the normal flow of control. A simple example from real life involves the following: Given a large (numerical analysis) program, determine how many times a floating point underflow occurs (for particular input) while simultaneously preserving the usual handling of underflows: setting the result to zero and continuing. The desired approach: writing a single underflow exception handler which increments a counter, zeros the result, and returns control to the point where the underflow occured, and then hanging this exception handler on the top level main routine. Aborting the calculation at the first underflow is unacceptable, as is decorating each and every line of the program with "catch UNDERFLOW; <increment counter>; resume" or some such variant. This sort of approach is possible with UNIX signals, but a good exception handling extension to the language should surely make resorting to 'signal' unnecessary. Obviously, allowing an exception handler to return to the point where the exception was raised means that one cannot unwind the call frame looking for a handler, and hence complicates the implementation. But any exception scheme which prohibits this usage seems (to me) to be like a two-legged chair - essentially useless. ------------------------------------------------------------------------ Laurence G. Yaffe lgy@pupthy.princeton.edu Department of Physics lgy@pucc.bitnet Princeton University ...!princeton!pupthy!lgy PO Box 708, Princeton NJ 08544 609-452-4371 or -4400
nevin1@ihlpf.ATT.COM (00704a-Liber) (03/30/88)
First off, this is not meant as a flame against Vance. It takes a lot of effort to come up with a proposal, and it is appreciated. But, Vance, you asked for criticism and now you are going to get it! :-) In article <8180006@eecs.nwu.edu> morrison@eecs.nwu.edu (Vance Morrison) writes: .A PROPOSAL FOR ADDING EXCEPTION HANDLING TO C++ . . Only three changes to the syntax of the language are necessary . . 1) Add the statement '_raise' to the language: . 1) Add the statement 'resume' to the language: . 2) Any statement can now be followed by the following construct . catch <statement> . For example . i = j/k; catch { printf("divide by zero error\n"); } . . As one might expect, '_raise' raises an exception, while 'catch' .declares a handler for a statement. Thus whatever statement precedes .'catch' is "protected", in the sense that if any exception is raised .in the protected statement, control is given to the statement after .'catch'. ... . After the statement after 'catch' is executed, _raise IS .IMPLICITLY CALLED. ... . This behavior is deliberate. The reasoning is that error .conditions should NEVER be ignored by default. Yes, but since you are already define a 'catch' routine you are obviously not ignoring the error condition. For this reason, I feel that the resume should be implicit and the _raise be explicit (BTW, if you _raise from a catch routine you should go to the next catch routine if there is one defined for the first catch routine). This is a minor point, though. .SYNTACTIC AMBIGUITIES . .In the following example . . for(i=0; i< 10; i++) { . printf("%d\n", err()); . } catch { . printf("error\n"); . resume; . } . . Is the 'catch' statement only protecting the printf, or .the whole for(;;) statement? Here we define it to be just the .printf statement. This seems to be inconsistent, since if you really wanted to protect only the printf("%d...), you could declare the catch just after it. You example should just catch if 'for' raises an exception (if the printf("%d...) has an error, no catch routine is called). If you want both the for statement and the printf("%d...) to be caught, putbrackets around the for statement and put the catch after the closing bracket (such as the way you do it for function bodies--see below). .FUNCTION BODIES .A function body is a legal statement to catch thus . . int main() . { . err(); . . return(0); . } catch { . printf("err\n"); . return(-1); . } . . Is legal and protects the whole function body. Note .that 'return' is a legal statement in a catch clause, and is .another way to escape from a catch clause (goto will also work). ... .****** PROGRAM USING MODULE **************************************** .#include <stdio.h> .#include "exception.h" .#include "example.h" . .main() .{ . /* call file_call and catch the FILE_ERROR FILE_NUMBERS */ . . file_call(); catch { . if (FILE_ERROR.is_raised()) { . printf("caught file error\n"); . resume; . } . if (FILE_NUMBERS.is_raised()) { . printf("caught file number error with param %d\n", . FILE_NUMBERS.number()); . resume; . } . } . . printf("done\n"); .} Unfortunately, this does not look all that much different from (using your file_call() function call as an example): if (BAD_VALUE == file_call()) { do some error processing } so I don't see that I am gaining all that much (although this may only be due to a poor choice of examples). The power of exceptions comes from being able to move error handling code away from the actual function calls. But, if this is to be done in the 'spirit of C++', it must: a) Be able to be translated into C b) Not incur much (or any, if possible) run-time overhead for code which doesn't use exception handlers c) Do something which cannot now be done in C++ or do something significantly better than it is already done in C++ and I don't think that your method can meet all these goals. I think that if you also proposed a method of implementation, we would be able to give you many more detailed, relevant comments. -- _ __ NEVIN J. LIBER ..!ihnp4!ihlpf!nevin1 (312) 510-6194 ' ) ) "The secret compartment of my ring I fill / / _ , __o ____ with an Underdog super-energy pill." / (_</_\/ <__/ / <_ These are solely MY opinions, not AT&T's, blah blah blah
ok@quintus.UUCP (Richard A. O'Keefe) (03/30/88)
In article <2229@phoenix.Princeton.EDU>, lgy@pupthy2.PRINCETON.EDU (Larry Yaffe) writes: > In article <8180006@eecs.nwu.edu> morrison@eecs.nwu.edu (Vance Morrison) writes: > >A PROPOSAL FOR ADDING EXCEPTION HANDLING TO C++ > [fairly reasonable proposal deleted] > As far as I can tell, this proposal for exception handling > (as well as exception handling in many other languages) fails to allow > a very basic form of exception handling that I regard as essential: > the ability for an exception handler to return control to the point > at which the exception was (first) raised and NOT disturb the normal flow > of control. This is a very strong requirement. How would you handle stack overflow in such a scheme? (Ok, you could reserve a handler stack, but what do you do if the handler returns?) In general, there are lots of exceptions which cannot sensibly be continued. Another example: addressing non-existent memory. > A simple example from real life involves the following: > Given a large (numerical analysis) program, determine how many times > a floating point underflow occurs (for particular input) while simultaneously > preserving the usual handling of underflows: setting the result to zero > and continuing. > This sort of approach is possible with UNIX signals... Er, no. Unless UNIX==BSD. There is no portable way for a System V program to find out what sort of floating-point error it got. (A SIGFPE might even mean _integer_ divide by zero.) There are also UNIX systems providing IEEE floating-point arithmetic where underflows and overflows and such don't give you exceptions. > But any exception scheme which prohibits this usage seems (to me) to be > like a two-legged chair - essentially useless. ADA is "essentially useless"? I must remember that. PL/I has this sort of handling scheme; in order to give you a way of trying to repair errors so that you could continue, PL/I has ever so many ON<thing> pseudo-variables. Try it, you'll hate it.
morrison@eecs.nwu.edu (Vance Morrison) (03/31/88)
This is in responce to the comments I have seen so far on my proposal for exception handling for C++. First may I say that I am glad to see such a good responce so soon. Second, I really must apologize for the incompleteness of my proposal. I realize that I really did not explain the semantics of the stack unwinding and other issues well (if at all). Instead I am relying on the interactive nature of the net to fill in the gaps as necessary. Here are some things that need clarification MEANING OF RAISING AN EXCEPTION First let me clarify what happens when an exception is raised. In my model a search goes on for the most closely nested 'catch' statement that protects the code in which the exception was raised.t The 'catch' clause is given control and unless the clase is exited (by using a 'return' 'goto' 'break' or 'resume' statement), the exception is implictly reraised. This causes a search for the next layer of 'catch'ing until either a catch clause is exited or the last chance handler is executed. MEANING OF RESUME There is some confusion about the meaning of 'resume' resume returns control to after the catch clause, NOT TO THE POINT WHERE THE EXCEPTION OCCURED. It is IDENTICAL to a goto statement that jumps right after the 'catch' clause. That is i = j/k; catch { printf("error\n"); resume; } printf("done\n"); Is equivalent to i = j/k; catch { printf("error\n"); goto out; } out: printf("done\n");
lgy@pupthy2.PRINCETON.EDU (Larry Yaffe) (03/31/88)
In article <837@cresswell.quintus.UUCP> ok@quintus.UUCP (Richard A. O'Keefe) writes: >In article <2229@phoenix.Princeton.EDU>, lgy@pupthy2.PRINCETON.EDU (Larry Yaffe) writes: >> As far as I can tell, this proposal for exception handling >> (as well as exception handling in many other languages) fails to allow >> a very basic form of exception handling that I regard as essential: >> the ability for an exception handler to return control to the point >> at which the exception was (first) raised and NOT disturb the normal flow >> of control. > >This is a very strong requirement. How would you handle stack overflow >in such a scheme? (Ok, you could reserve a handler stack, but what do >you do if the handler returns?) In general, there are lots of exceptions >which cannot sensibly be continued. Another example: addressing >non-existent memory. Certainly there are exceptions which cannot sensibly be continued. However, since there are also exceptions which CAN sensibly be continued, I would greatly prefer any exception handling language extension to permit continuation. I regard your example of `non-continuable' stack overflow with some amusement - since I view this as excellent example of an exception which should be continuable (if, of course, the handler can first dynamically extend the stack). Some operating systems do this all the time; I would like to be able to do the same thing cleanly and easily within a good progarmming language. >> A simple example from real life involves the following: >> Given a large (numerical analysis) program, determine how many times >> a floating point underflow occurs (for particular input) while simultaneously >> preserving the usual handling of underflows: setting the result to zero >> and continuing. >> This sort of approach is possible with UNIX signals... >Er, no. Unless UNIX==BSD. There is no portable way for a System V >program to find out what sort of floating-point error it got. (A SIGFPE >might even mean _integer_ divide by zero.) There are also UNIX systems >providing IEEE floating-point arithmetic where underflows and overflows >and such don't give you exceptions. Perfectly true. That's why I'd like to be able to do this solely within C++. >> But any exception scheme which prohibits this usage seems (to me) to be >> like a two-legged chair - essentially useless. >ADA is "essentially useless"? I must remember that. While my analogy may be just slightly exaggerated (:-), the important qualifier was "to me". And yes, PERSONALLY, I regard Ada as "essentially useless". Your mileage may vary. >PL/I has this sort of handling scheme; in order to give you a way of >trying to repair errors so that you could continue, PL/I has ever so >many ON<thing> pseudo-variables. Try it, you'll hate it. Your're quite right - nearly everything I know about PL/I convinces me I don't want to use it. But that doesn't mean there arn't good ideas floundering in that swamp of a language. ------------------------------------------------------------------------ Laurence G. Yaffe lgy@pupthy.princeton.edu Department of Physics lgy@pucc.bitnet Princeton University ...!princeton!pupthy!lgy PO Box 708, Princeton NJ 08544 609-452-4371 or -4400
morrison@accuvax.nwu.edu.UUCP (Vance Morrison ) (03/31/88)
This is in response to the comments I have seen so far on my proposal for exception handling for C++. First may I say that I am glad to see such a good response so soon. Second, I really must apologize for the incompleteness of my proposal. I realize that I really did not explain the semantics of the stack unwinding and other issues well (if at all). Instead I am relying on the interactive nature of the net to fill in the gaps as necessary. Here are some things that need clarification MEANING OF RAISING AN EXCEPTION First let me clarify what happens when an exception is raised. In my model a search goes on for the most closely nested 'catch' statement that protects the code in which the exception was raised.t The 'catch' clause is given control and unless the catch is exited (by using a 'return' 'goto' 'break' or 'resume' statement), the exception is implicitly reraised. This causes a search for the next layer of 'catch'ing until either a catch clause is exited or the last chance handler is executed. MEANING OF RESUME There is come confusion about the meaning of 'resume'. Resume returns control to the statement after the 'catch' clause, NOT TO THE POINT WHERE THE EXCEPTION WAS RAISED! For example these two structures are equivalent i=j/k; catch { printf("error"); resume; } printf("done"); is equivalent to i=j/k; catch { printf("error"); goto out; } out: printf("done"); MY RESPONSE TO COMMENTS: Here I will respond to some comments I have seen, If I misrepresent anyone, I am sorry, please let me know. IN RESPONSE TO LARRY YAFFE'S COMMENTS: Larry Yaffe is concerned that my proposal does not allow restart capability (that is the ability to continue from the point at which the exception occurred). In response may I say 1) My proposal does NOT exclude the possibility of adding a restart capability. By adding a keyword 'restart' (or whatever) it could be added. 2) Second, I have found personally, that restart capability is not indispensable, and usually not very useful. Usually, you want to restart the problem from the beginning if a fatal error occurs, and if you want the restart from the middle, you can always pass back state information so that the procedure can be called "in the middle", (I can provide an example if you like). 3) Because the exception was raised, the procedure is telling you that it cannot continue normally. Therefore the handler must "fix" the problem before it can continue. Providing mechanisms for this is a nasty problem. 4) Restart is quite a bit more complicated to implement, since destructors CANNOT be called until you can be sure a restart is not pending. In general its a mess. I have found personally that exceptions without restart are QUITE useful, so we should implement that first. If we find we need restart, we can add it as an option. IN RESPONSE TO NEVIN LIBER'S COMMENTS Nevin Had several comments, the first of which was to question my reasoning on the default '_raise' at the end of a 'catch' statement. This is a very important point, and I would like to clarify it. First the '_raise' an 'catch' statements are really just tools for building "real exceptions" and although '_raise' and 'catch' only implement a single unnamed exception, it is easy to extend as I have done to provide Named exceptions. Thus a 'catch' clause will almost always have the form <statement> catch { if (is_raised(EXCEPTION1) { <handle exception 1> resume; } else if(is_raised(EXCEPTION2) { <handle exception 2> resume; } } That is I am only prepared to handle certain exceptions I know about (or groups of exceptions, or exceptions with certain attributes), The rest I don't know how to handle so I should pass them on to someone who does (by reraising). The alternative is that the programmer must explicitly reraise the exception. The code would look like <statement> catch { if (is_raised(EXCEPTION1) { <handle exception 1> } else if(is_raised(EXCEPTION2) { <handle exception 2> } else _raise; } Now if the programmer forgot to put the _raise, he is implicitly ignoring all errors he can't handle. THAT IS JUST THE PROBLEM I WANT TO SOLVE. The problem with return codes is that the are all to easy to ignore, and numerous bugs and cryptic program crashes are the result. The beauty of exceptions is that the default action for an exception is defined by the module designer and unless the module user EXPLICITLY catches the exception, that default action is taken. Nevin also did not like my binding in the case of for(i=0; i<10; i++) printf("test\n"); catch { printf("error"); } The question is does catch protect just the printf or the entire for statement. I defined it to be just the printf (that is catch binds to the smallest statement). In some ways this is an arbitrary decision, but I believe that this binding is the more common, so is a better choice. Finally Niven felt that Exceptions that I define have little advantage over return codes. He obviously hasn't used them (:-). Part of the problem is my example was trivial The big advantages in my opinion are: 1) Exceptions can travel up more that one stack frame, so that you don't need code like the fragment below every time you call a function ret = some_function(); if (ret != SUCCESS) return(ret); 2) If a programmer uses a module, IF HE DOES NOTHING errors will be handled in a default way (ie printed out). With error codes, the default action is it ignore the error. 3) Exceptions can easily have parameters, a BIG plus. **************************************************************************** Nevin has asked for an implementation of my exception handling. I do indeed have an all the major parts of an implementation. This implementation is a preprocessor for C++ that uses 'asm()' statements into the code at proper places which leave lables for the boundaries of protected regions. But that is not the point of my proposal, There are many implementation of exception handling that could be used. What I want to establish the syntax for the end result. Thats all for now. Vance Morrison
morrison@eecs.nwu.edu (Vance Morrison) (03/31/88)
ADDITION TO THE PROPOSAL,
I recieved a letter which made me realize that a small
addition to my proposal should be made. Originally the syntax for
the 'catch' statement was
<statement> catch <exception handler statement>
I would like to extend it to be
<statement> catch
<exception handler statement> [ else <no exception statement> ]
Where the else clause is optional.
This makes things like looping on exceptions easy
for(;;) {
<statement> catch resume;
else break;
}
Vance Morrison
pabuhr@watmsg.waterloo.edu (Peter A. Buhr) (03/31/88)
In article <2229@phoenix.Princeton.EDU> lgy@pupthy2.PRINCETON.EDU (Larry Yaffe) writes: >In article <8180006@eecs.nwu.edu> morrison@eecs.nwu.edu (Vance Morrison) writes: >>... > As far as I can tell, this proposal for exception handling >(as well as exception handling in many other languages) fails to allow >a very basic form of exception handling that I regard as essential: >the ability for an exception handler to return control to the point >at which the exception was (first) raised and NOT disturb the normal flow >of control. A simple example from real life involves the following: > >... Now, you see, I don't consider this situation as an exception. PL/I handles this using ON CONDITIONS, which are not exception, but dynamically bound procedure calls. Exceptions alter the normal prescribed flow of control in a program. All you want is to invoke a user defined routine whenever an underflow occurs. Hence, the hardware calls some routine when it discovers an overflow and you are allowed to change which routine gets called. In PL/I, there is a essentially a procedure variable called OVERFLOW (or something like that) which PL/I initializes to a routine that prints an error message and then aborts execution which might be done by raising an exception to alter the flow of control to the system (PL/I does not do this, it just sets fire to your program and walks away). You are allowed to reassign the value of this procedure variable to your own routine. So you can count the number of overflows and possible reset the erroneous value to anything you like and then return back to the hardware to continue execution. PL/I makes it all complex by using dynamic binding to determine which procedure named OVERFLOW to executed, but that's another issue.
eric@snark.UUCP (Eric S. Raymond) (03/31/88)
In article <8180006@eecs.nwu.edu>, morrison@eecs.nwu.edu (Vance Morrison) writes: >PROPOSAL: [for exception-handling in C] I like the basic idea of a C analogue of LISP throw/catch, but: 1) I'm not clear how this offers more capability than setjmp/longjmp. 2) I think your catch syntax is un-C-like; no other construct in the language makes that kind of link between adjacent statements. I think that making 'catch' an if-like construct would fit C better; i.e instead of > i = j/k; catch { printf("divide by zero error\n"); } I suggest catch { i = j / k; } do { printf("divide by zero error\n"); } I think this is easier to read, and resolves in a more elegant way the syntactic difficulties you've noted. On the positive side, I do believe (from my LISP experience) that this is a suitable 'most primitive' exception-handling mechanism for environments with only a single control thread (for multiple-thread environments you need to support *named* exceptions, because a common global exception-type variable could get fandangoed on). -- Eric S. Raymond (the mad mastermind of TMN-Netnews) UUCP: {{uunet,rutgers,ihnp4}!cbmvax,rutgers!vu-vlsi}!snark!eric Post: 22 South Warren Avenue, Malvern, PA 19355 Phone: (215)-296-5718
bruce@psldev.Dayton.NCR.COM (bruce frederiksen) (04/01/88)
In article <837@cresswell.quintus.UUCP> ok@quintus.UUCP (Richard A. O'Keefe) writes: >In article <2229@phoenix.Princeton.EDU>, lgy@pupthy2.PRINCETON.EDU (Larry Yaffe) writes: >> In article <8180006@eecs.nwu.edu> morrison@eecs.nwu.edu (Vance Morrison) writes: >> >A PROPOSAL FOR ADDING EXCEPTION HANDLING TO C++ >> [fairly reasonable proposal deleted] >> As far as I can tell, this proposal for exception handling >> (as well as exception handling in many other languages) fails to allow >> a very basic form of exception handling that I regard as essential: >> the ability for an exception handler to return control to the point >> at which the exception was (first) raised and NOT disturb the normal flow >> of control. > >This is a very strong requirement. How would you handle stack overflow >in such a scheme? (Ok, you could reserve a handler stack, but what do >you do if the handler returns?) In general, there are lots of exceptions >which cannot sensibly be continued. Another example: addressing >non-existent memory. You've offered a solution to the stack overflow problem. Your other example, addressing non-existent memory, is one that I could use in a project I'm working on here. What I want to do is dynamically allocate shared memory blocks that are used as shared heap space by several processes. When one process finds the heap exhausted, he creates a new shared memory block (much like malloc doing an sbrk), attaches it, initializes it and allocates his whatever. He then chains this new whatever to the shared list of whatevers that these processes are using. Now another process takes control and starts reading down this list and jumps off the end into the new shared memory block that he hasn't attached yet. Easiest way to handle this would be to have an exception handler in each process to handle "addressing non-existent memory". It just attaches the new shared memory block and then returns back to the program as if nothing had happened. On a whole, I don't think that an exception mechanism should be built into the language. Any exception mechanism can be built in C++ to do whatever you or I or anybody else might want except for two things: 1. The standard setjmp/longjmp routines don't execute destructor functions for objects in the intermediate (aborted) functions. 2. (as you have said) Numerical exceptions (divide by 0, overflow, underflow) are not reported in C. You could write protected numbers with operators that check for these things, but it may not be as efficient as it could be when there is hardware support for these. I think that the first problem is at the real crux of exception mechanisms. Once it is solved, exception mechanisms in the form of libraries can be written without cluttering the language. Then if you are not happy with how I've implemented my exception mechanism you are not forced to use it. One solution to the first problem might involve using two parallel stacks: one for objects with destructors and one for everything else. Then the longjmp can fire up the destructor functions of all the objects in the one stack (down to the function being returned to) without worrying about all of the other clutter in the stack. This assumes that the destructor function and length of any object on the stack can be determined given just its address. Virtual functions handle this just fine. So if you're willing to live with virtual destructors and length functions this can all be done in C++ without changing the language. If anybody else has a solution to the setjmp/longjmp problem, I'd like to hear it. -bruce.frederiksen@Dayton.NCR.COM NCR Corp, SE-Retail, Dayton
steve@vsi1.UUCP (Steve Maurer) (04/01/88)
Article 303 of comp.lang.c++: Path: vsi1!steve From: steve@vsi1.UUCP (Steve Maurer) Newsgroups: comp.lang.c++ Subject: Re: Proposal for Exceptions for C++ Message-ID: <457@vsi1.UUCP> Date: 31 Mar 88 19:26:58 GMT References: <8180006@eecs.nwu.edu> <2229@phoenix.Princeton.EDU> <837@cresswell.quintus.UUCP> <2243@phoenix.Princeton.EDU> Reply-To: steve@vsi1.UUCP (Steve Maurer) Organization: Vicom Systems Inc. San Jose, Cal. Lines: 71 I have a question. What's wrong with doing this? Have an exception keyword: "exception", placed before the exception processing function. Have a identifier following which is the "name" of the exception (much like structure identifiers). Have a couple of predefined identifiers for the most common exceptions: divide by zero, stack overflow, etc. use "raise" with these identifiers. redefine "resume" to not disturb the flow of control Example Of Use: extern int counter; extern int result; exception userfoobar /* a user defined exception */ { counter--; } exception zerodivide /* zerodivide is a predefined exception */ { /* ...raised on divide by zero errors */ counter++; result = 0; if (counter > 200) exit(); resume; /* actually a redundant statement, resume is implicit */ } exception noresume /* noresume is a predefined exception */ { /* ...raised when resuming generates an */ printf("error could not resume\n"); /* immediate error */ exit(-1); } // exit is also redundant in this case, a few predefined // exceptions are automatically fatal (they exit no matter what) //--------------- int counter, result; main(int ac; char **av) /* example use */ { float foo[1000], bar[1000]; int i; getinputarray(foo); /* inputs data from somewhere */ getinputarray(bar); for (i = 0; i < 1000; i++) { result = foo[i] / bar[i]; /* raises exception on / by 0 */ /* any other processing */ /* increments counter */ } raise zerodivide; /* raise a divide by zero exception */ raise userfoobar; /* raise a userfoobar exception */ } This is simple to use, powerful (though not quite complete), and would not be too much of a pain to translate into any reasonable C implementation (using signals/longjmps). Steve Maurer tolerant!vsi1!steve octopus!vsi1!steve
daniels@teklds.TEK.COM (Scott Daniels) (04/01/88)
In article <2229@phoenix.Princeton.EDU> lgy@pupthy2.PRINCETON.EDU (Larry Yaffe) writes: >... As far as I can tell, this proposal for exception handling >(as well as exception handling in many other languages) fails to allow >a very basic form of exception handling that I regard as essential: >the ability for an exception handler to return control to the point >at which the exception was (first) raised and NOT disturb the normal flow >of control.... The problem with this approach is that it dictates a substantial change in the C language implementation requirements. Without this capability, all C variable accesses may be reached either by a global access (typically an absolute address), or as addresses relative to a stack pointer (for auto variables). With this requirement, the "catch statement" must be able to access the locals for the function in which it is executing, while still maintaining a stack depth that allows returning to the original function. Note that this problem exists by implication in the stated design since the default handler "prints the stack"... If the stack is abandoned (as an alternate return mechanism might reasonably do), there is nothing left to print. Managing a stack that happens from this code would be a nightmare: main(argc, argv) int argc; char **argv; { something() catch { foo( mumble(), fumble() ) catch { printf("Oops: %s caught in catch\n", argv[0]); if( random() > 0.5 ) resume_original; if( random() > 0.5 ) resume_here; printf( "catch in catch completed.\n" ); } printf( "catch completed.\n" ); } printf( "main completed.\n" ); } -Scott Daniels daniels@teklds.UUCP
lgy@pupthy2.PRINCETON.EDU (Larry Yaffe) (04/01/88)
In article <17935@watmath.waterloo.edu> pabuhr@watmsg.waterloo.edu (Peter A. Buhr) writes: >In article <2229@phoenix.Princeton.EDU> lgy@pupthy2.PRINCETON.EDU (Larry Yaffe) writes: [An example involving counting underflows] >Now, you see, I don't consider this situation as an exception. PL/I >handles this using ON CONDITIONS, which are not exception, but >dynamically bound procedure calls. [More PL/I info deleted] I am curious about whether most people agree with this distinction concerning the meaning of an exception. To me, an "exception" indicates that something exceptional happened, possibly needing some intervention (a handler), but not necessarily something "disasterous" (i.e., requiring major alteration in the flow of control). From the language design viewpoint, it seems arbitrary and unpleasant to force a distinction between "dynamically bound procedure calls" - possibly triggered by hardware traps - and "real" exceptions. Other opinions? ------------------------------------------------------------------------ Laurence G. Yaffe lgy@pupthy.princeton.edu Department of Physics lgy@pucc.bitnet Princeton University ...!princeton!pupthy!lgy PO Box 708, Princeton NJ 08544 609-452-4371 or -4400
gore@eecs.nwu.edu (Jacob Gore) (04/01/88)
/ comp.lang.c++ / lgy@pupthy2.PRINCETON.EDU (Larry Yaffe) / Mar 31, 1988 / >In article <17935@watmath.waterloo.edu> pabuhr@watmsg.waterloo.edu (Peter A. Buhr) writes: >>Now, you see, I don't consider this situation as an exception. PL/I >>handles this using ON CONDITIONS, which are not exception, but >>dynamically bound procedure calls. > >[...] To me, an "exception" indicates >that something exceptional happened, possibly needing some intervention >(a handler), but not necessarily something "disasterous" (i.e., requiring >major alteration in the flow of control). From the language design >viewpoint, it seems arbitrary and unpleasant to force a distinction >between "dynamically bound procedure calls" - possibly triggered by >hardware traps - and "real" exceptions. Actually, I think it's a very nice distinction. There are languages where one can make heavy use of procedures activated on certain conditions -- for example, when a variable's value changes. Their activation not only indicates nothing disasterous, but nothing exceptional, either. I am having some trouble classifying your example (counting overflows). Overflows are USUALLY associated with exceptional situation. However, if you expect that overflows are not unlikely to happen -- if you didn't, why would you want to count them? -- then I would not consider overflows exceptional. (I'm not sure what all this has to do with dynamic binding of procedure calls, but that's another story...) Jacob Gore Gore@EECS.NWU.Edu Northwestern Univ., EECS Dept. {oddjob,gargoyle,ihnp4}!nucsrl!gore
gore@eecs.nwu.edu (Jacob Gore) (04/02/88)
/ comp.lang.c++ / steve@vsi1.UUCP (Steve Maurer) / Mar 31, 1988 / >What's wrong with doing this? ... >Example Of Use: ... >exception userfoobar /* a user defined exception */ >{ >counter--; >} Well, it's not that it's "wrong," but that it could be so much better. Exceptions can be objects in their own right. That would permit one to have sets, prioritized lists, whatever of exceptions. Your solution provides very inflexible exception handling. You are trying to make an exception handler look like a procedure. But in C, that makes it even more restrictive than the arrangement used in Ada: Not only are you restricting how exceptions can be organized, but you are also allowing for only one possible way to handle each exception! Jacob Gore Gore@EECS.NWU.Edu Northwestern Univ., EECS Dept. {oddjob,gargoyle,ihnp4}!nucsrl!gore
keith@nih-csl.UUCP (keith gorlen) (04/02/88)
In article <8180002@accuvax.nwu.edu.UUCP>, morrison@accuvax.nwu.edu.UUCP (Vance Morrison ) writes:
->
-> Nevin has asked for an implementation of my exception handling.
-> I do indeed have an all the major parts of an implementation. This
-> implementation is a preprocessor for C++ that uses 'asm()' statements
-> into the code at proper places which leave lables for the boundaries
-> of protected regions.
That's the easy part. How does your implementation arrange to execute
the destructors of class objects that go out of scope as a result of
an exception?
--
Keith Gorlen phone: (301) 496-5363
Building 12A, Room 2017 uucp: uunet!ncifcrf.gov!nih-csl!keith
National Institutes of Health Internet: keith%nih-csl@ncifcrf.gov
Bethesda, MD 20892
morrison@eecs.nwu.edu (Vance Morrison) (04/03/88)
Hello, This is in reply to Steve Maurer's suggesting on making exceptions look like functions. There are several problems 1) It does not allow more than one exceptions handler to be defined for a given exception. (if a given exception is declaired more than once, which one should it choose?) 2) MOST times, when an exception is raised, you want to return to the scope of a functions somewhere above you on the stack, how do you do this? (longjumps won't work since they do not call destructors properly) 3) Often you need access to variables that are in the scope of functions above you in the call stack to handle the error properly. How can you do this? In my mind, exceptions are FLOW OF CONTROL constructs. They allow you to 'goto' places out of your scope in a controled way. exceptions are not functions or data structures, they are more like fancy 'goto' statements. Vance Morrison Northwestern Univ.
dwaitzma@bbn.com (David Waitzman) (04/05/88)
In nnsc.nsf.net pub/exceptions.PS (available via anonymous ftp) is a (drafty) paper (in postscript) on adding exceptions to a language built upon C++: Avalon. The paper also examines adding exceptions to C++ directly. Some of the ideas presented in the paper have been discussed with (the) Bjarne. If anyone wants, I can mail them a copy of the paper directly. -david ------- The paper was written when I was a student at Carnegie Mellon. BBN Labs, Inc. has no opinion on this (as far as I know).
johna@cognos.uucp (John Anderson) (04/06/88)
In article <8180006@eecs.nwu.edu> morrison@eecs.nwu.edu (Vance Morrison) writes: >A PROPOSAL FOR ADDING EXCEPTION HANDLING TO C++ What about destructors?? Aren't they one of the key problems to be delt with in an exception handling mechanism? -- John Anderson, Cognos Incorporated, P.O. Box 9707, 3755 Riverside Drive, Ottawa, Ontario, CANADA K1G 3Z4 (613) 738-1440 decvax!utzoo!dciem!nrcaer!cognos!johna
wyant@apollo.uucp (Geoffrey Wyant) (04/06/88)
I have two problems with the exception mechanisms proposed so far. First and foremost, most of them don't seem to have been well thoughtout semantically. The majority of them seem to think up some syntax for raising and catching exceptions and supply a few trivial examples to illustrate the semantics. Nobody has really said what an exception is, is it a globally defined indentifier, an object or what ? Secondly, or exception handlers statically or dynamically bound ? Designing a good exception mechanism is difficult and touches on a large number of semantic issues. The other problem I have with the proposals is that these ill-defined exceptions aren't being treated first class entities in the language. Why should I be able to subclass exceptions. Its very usefull to do. This enables you to organize and catagorize exceptions. Well, enough ramblings and rantings. -- Geoff -- UUCP: ...{yale,mit-eddie}!apollo!wyant
pierson@encore.UUCP (Dan Pierson) (04/07/88)
In article <22999@bbn.COM> dwaitzma@vax.BBN.COM (David Waitzman) writes: >In nnsc.nsf.net pub/exceptions.PS (available via anonymous ftp) is a >(drafty) paper (in postscript) on adding exceptions to a language >built upon C++: Avalon. The paper also examines adding exceptions to >C++ directly. Some of the ideas presented in the paper have been >discussed with (the) Bjarne. Your proposal is almost the best so far. It certainly does the best job of integrating exceptions into the C++ class system. However, there is one part of the proposal which I strongly dislike: exceptions are only propogated a single call level. This causes code written using exception handling to be almost as verbose, hard to read, and hard to maintain as code using special return values. The biggest possible win with this approach is that instead of having to follow every call which wishes to check errors with a block of error handling code, you have to follow every block which wishes to check errors with a block of error handling code. Much of this code will include something like: ... default: ex->raise(); ... In fact, in many cases that may be the entire contents of the exception clause! Consider the following case: We're about to perform an atomic action of some sort. The top level code sets up the atomic block in some way and calls one or more lower level routines to perform the action. These routines then call other routines, etc. Several call levels down a routine runs out of a critical resource, say memory or disk space. In the context of this application the correct thing to do is back out the current action and let the top level routine try and get more resource, say by cleaning up or asking the user for help. What I'd like to do is have all the lower level routines proceed with no knowledge of this possible problem __except__ for providing finalization methods which undo all of their work (which should only be resource allocation at this level). The exception would propogate up to the handler in the top level routine, cleaning things up as it goes, and the top level handler would then try to get more of the resource and try the action again (or raise its own exception). With your proposal, every single routine would have to have an exception block which explicitly re-raised all exceptions. This would add to the code bulk, thus camouflaging the local algorithms to no benefit. -- In real life: Dan Pierson, Encore Computer Corporation, Research UUCP: {talcott,linus,necis,decvax,ihnp4}!encore!pierson Internet: pierson@multimax.arpa
steve@vsi1.UUCP (Steve Maurer) (04/08/88)
> This is in reply to Steve Maurer's suggesting on making >exceptions look like functions. > >There are several problems > 1) It does not allow more than one exceptions handler to be > defined for a given exception. (if a given exception is > declaired more than once, which one should it choose?) Presumably, this would fail to compile. If you wanted two behaviors out of your exception handler, you would have to use an 'if' statement. > 3) Often you need access to variables that are in the scope > of functions above you in the call stack to handle the > error properly. How can you do this? The C++ compiler (translator) would look to upper scopes for the variable name you requested. If found, it would record the procedure name, variable offset, and record this as arguments to a run-time routine that would return the variable's value. Of course this would work for automatic variables only. > 2) MOST times, when an exception is raised, you want to > return to the scope of a functions somewhere above you > on the stack, how do you do this? (longjumps won't work > since they do not call destructors properly) Even though the original article didn't have a keyword to do this, it should have been added. As for implementation, though this is difficult, it could be done. Basically, the C++ translator would have to generate a call to one of 2 runtime functions, which either searched for a named procedure, or simply returned up one or more levels. Both would have to call destructors during run time. Of course, this *still* doesn't give us everything we want, but I have been laboring under the assumption that most people want a construct that can be translated into C ( by one of the popular translators out there ), and I don't think that you can get everything you want and still do this. Steve Maurer p.s. I don't think anything we discuss here, ever *really* has a chance of being adopted, so I'm not sure why I bother.
jima@hplsla.HP.COM ( Jim Adcock) (04/08/88)
| That's the easy part. How does your implementation arrange to execute | the destructors of class objects that go out of scope as a result of | an exception? Well now, there seems to be several people who claim to have solutions to the C++ exception problem, but I have yet to see anyone explain how to call destructors for the objects going out of scope. If someone HAS figured out a good solution to this problem, how about a quick explanation? [under the restriction that any object on the stack (that needs to be destroyed when an exception trashes its environment) has a vtable, this problem becomes quite doable. Anybody have found a less restrictive (and reasonable) solution? ]
tecot@Apple.COM (Ed Tecot) (04/08/88)
In article <22999@bbn.COM> dwaitzma@vax.BBN.COM (David Waitzman) writes: >In nnsc.nsf.net pub/exceptions.PS (available via anonymous ftp) is a >(drafty) paper (in postscript) on adding exceptions to a language >built upon C++: Avalon. The paper also examines adding exceptions to >C++ directly. Some of the ideas presented in the paper have been >discussed with (the) Bjarne. If anyone wants, I can mail them a copy >of the paper directly. Funny how I see this and get your mail at the same time... Yes, Stanford is near Apple. I may not be around the weekend of the 16th, but you can try to get in touch with me. My phone is 408-973-5418 work and 408-739-4240 at home. Please bring a copy of the paper too. _emt
keith@nih-csl.UUCP (keith gorlen) (04/09/88)
In article <6590029@hplsla.HP.COM>, jima@hplsla.HP.COM ( Jim Adcock) writes:
-> Well now, there seems to be several people who claim to have solutions
-> to the C++ exception problem, but I have yet to see anyone explain how
-> to call destructors for the objects going out of scope.
-> ...
-> [under the restriction that any object on the stack (that needs to be
-> destroyed when an exception trashes its environment) has a vtable,
-> this problem becomes quite doable. Anybody have found a less
-> restrictive (and reasonable) solution? ]
How does heving a vtable help?
--
Keith Gorlen phone: (301) 496-5363
Building 12A, Room 2017 uucp: uunet!ncifcrf.gov!nih-csl!keith
National Institutes of Health Internet: keith%nih-csl@ncifcrf.gov
Bethesda, MD 20892
chris@mimsy.UUCP (Chris Torek) (04/10/88)
In article <6590029@hplsla.HP.COM> jima@hplsla.HP.COM (Jim Adcock) writes: >Well now, there seems to be several people who claim to have solutions >to the C++ exception problem, but I have yet to see anyone explain how >to call destructors for the objects going out of scope. What is needed is a generic `unwind-protect' (not necessarily in the language itself, but certainly for the compiler). The code generated will then look something like this (pseudo C++ syntax): /* object o; protection p: */ if (unwind_protect(&p)) { o.~o(); unwind_resume(&p); } o.o(); ... o.~o(); remove_protection(&p); It is important that the `unwind_protect' and `remove_protection' operations be fast, as these could occur quite often. In stack architectures this can usually be done with `protection objects' and address arithmetic. Something like the following can be made to work: struct protection { struct protection *outer; /* outer protection(s) */ jmp_buf label; /* context */ } InnermostProt; /* current innermost active protection */ #define unwind_protect(p) \ ((p)->outer = InnermostProt, \ InnermostProt = (p), \ setjmp((p)->label)) #define remove_protection(p) (InnermostProt = (p)->outer) /* * unwind compares each stack frame with InnermostProt * to see if there is a protection frame there, and if so * jumps to it. unwind_resume can be optimised if necessary * by noting when protections belong to the same frame. */ There remains the problem that the object may be in any of three `improper' states (not constructed, only partially constructed, or partially destroyed) at the time the exception causes the stack to be unwound past the protection markers. There appear to be only two cures: either defer the unwinding (and hence the entire exception process) until the object is stable, or ensure that the con- and de-struction processes use only atomic operations. The former approach fails in the general case (exceptions during -struction either oscillate or fail utterly); the latter is just plain hard, even with help from the programmer. -- In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163) Domain: chris@mimsy.umd.edu Path: uunet!mimsy!chris
jima@hplsla.HP.COM ( Jim Adcock) (04/12/88)
|| [under the restriction that any object on the stack (that needs to be || destroyed when an exception trashes its environment) has a vtable, || this problem becomes quite doable. Anybody have found a less || restrictive (and reasonable) solution? ] | |How does having a vtable help? The short [partial] answer: Having a vtable for an cleanup-able object -- aka insisting that objects that are to be destroyed when an exception trashes its environment have one or more virtual virtual functions defined on that object -- allows "all" of the questions necessary to sucessfully destroy an object to be answered by the "object" itself. The questions that must be answered by that object are probably: 1) am "I" an object? 2) do I need to have a "destruction" operation applied to me upon my death? 3) what is the "destruction" operation that needs to be applied upon my death? 4) how big am I? Also, note the following discussion [which I generally agree with] before I give more details: |On a whole, I don't think that an exception mechanism should be built into |the language. Any exception mechanism can be built in C++ to do whatever |you or I or anybody else might want except for two things: | | 1. The standard setjmp/longjmp routines don't execute destructor | functions for objects in the intermediate (aborted) functions. | | 2. (as you have said) Numerical exceptions (divide by 0, overflow, | underflow) are not reported in C. You could write protected | numbers with operators that check for these things, but it may | not be as efficient as it could be when there is hardware | support for these. | |I think that the first problem is at the real crux of exception mechanisms. |Once it is solved, exception mechanisms in the form of libraries can be |written without cluttering the language. Then if you are not happy with |how I've implemented my exception mechanism you are not forced to use it. | |One solution to the first problem might involve using two parallel stacks: |one for objects with destructors and one for everything else. Then the |longjmp can fire up the destructor functions of all the objects in the one |stack (down to the function being returned to) without worrying about all |of the other clutter in the stack. This assumes that the destructor |function and length of any object on the stack can be determined given just |its address. Virtual functions handle this just fine. So if you're |willing to live with virtual destructors and length functions this can all |be done in C++ without changing the language. | |If anybody else has a solution to the setjmp/longjmp problem, I'd like to |hear it. The parts of the above discussion I don't totally agree with are 1) I wouldn't consider support of two parallel stacks to be an acceptable solution, since in my mind this would diverge too much from standard language implementations and 2) I don't consider lack of detection of an error condition E on a machine M's implementation of C[++] in an operating system U to be part of the "exception handling" problem in the C++ language. Note, however, I might be able to be convinced that the second stack [for objects requiring destruction] could be successfully simulated by maintaining a linked-list of destructable objects on heap (although this is starting to sound enough like other "garbage-collecting" languages to make me nervous). Alternately, note that one stack would be sufficient if the objects on a "dead" region that stack that need to be "destroyed" can be reliably detected. If you were to use the heap-based approach, I think your heap would need to be buddy-system, as I believe the g++ implementation of heap is. So to my mind two "solutions" to the "clean-up on exception" problem might be: 1) maintain a linked list of "destructable" objects in heap space, portions of that list to be "destructed" when their corresponding environments get killed by an exception. 2) provide a way to "reliably" detect objects in the standard stack that need to be destroyed when their corresponding environments get killed by an exception. If the following psuedo-code can be "reliably" implemented then the standard stack can be used: pointer p = "bottom"-of-killed-region of stack while p <= "top"-of-killed-region-of stack { if (is-valid-destructable-object(*p) && p->needs-destruction()) { pstep = p->size(); p->destroy(); p += pstep; } else ++p; } If this is indeed a "solution", one might productively ask what it is I think I am solving (since every author addressing C++ "exceptions" seems to have a different idea of what the problem "is" and "isn't"). I don't consider the following to be a necessary part of MY conception of the essential "exception-handling" problem in C++ : - provide the "best" possible syntax for exception handling as a new construct within C++ - provide a new, alternative, unstructured flow of control mechanism to programmers who have been cruelly denied the use of goto statements by the force of public opinion :-) - provide a "built-in" exception handling capability in C++ - provide an exception handling technique [routines, libraries ...] that can be trivially ported between machines. - provide a single base class for all "objects" - provide an "exception handling capability" that will still succeed in the face of a deliberately malicious user[/abuser] [Since C/C++ already allows deliberately malicious users to hose pretty much whatever they want to hose] - provide for the "trivial" programming of the failure case where an exception is raised during the construction/destruction of an object which itself needs to be cleanly destroyed when an exception occurs. I do consider the following to be a necessary part of MY conception of the essential "exception-handling" problem in C++: - provide a reasonably simple way for motivated C++ programmers to catch and recover from general software or hardware problems that could not be reasonably anticipated and coded as part of the standard coding process. The goal is to recover from what would otherwise be an untimely death of the executing program. Since this definition of "exceptions" describes a truly "exceptional" situation, the cost for recovering from this unfortunate circumstance need not be optimal in terms of recovery time. - provide "exception handling" that can be used to catch errors in existing C/C++/Pascal/Fortran/etc libraries without having to recompile these libraries [IE no change in the traditional design of global/stack/heap spaces] - provide exception handling at "zero cost" for people who aren't using it. - provide exception handling at "VERY low cost" in terms of execution speed when "exception" conditions aren't occuring. - provide exception handling at "zero cost" in size and speed for objects that don't need to be "destructed" when an exception occurs. - provide exception handling at "very low cost" in size for objects that do need to be "destructed" when an exception occurs - provide for destruction of the "dying" objects on the stack at "reasonable" cost when an exception destroys their environment. Given the above definition of the "exception handling" problem my claim is that a sufficient solution is probably something like: 1) A setjump/longjump type capability. 2) Foundation class[es] which define the above discussed virtual functions along with any necessary class variables to implement those virtual functions. 3) A routine to search the dying region of stack for "objects" that require "destruction" when an exception kills their region of stack. 4) Ways for exceptional conditions to alter flow-of-control and invoke the stack-sweep routine over the appropriate dying region of stack. So I'm not [yet] convinced that exception handling capabilities should be "built-in" to C++. I have a very crude, preliminary, [not-very-portable], example of a C++ routine to sweep a "dying" region of stack and to search-and-destroy those objects requiring destruction; along with a compatible [minimal] base class. This example might be of some interest to people very motivated to work on "solving" the "exception handling" problem on their machines.