"Rock-a-bye function, on the call stack, When you get called, there won't be a catch. When a call throws, an exception will fall, And down will come function, program, and all."
There's been a lot of discussion about exceptions here, and the consensus is that they should be thrown only in exceptional conditions. Unfortunately, there seems to be little consensus as to what "exceptional" really means.
Personally, I never use exceptions (too many paths of execution to worry about, as seen in the latest Guru of the Week). However, I realize that people using my code might prefer to deal with them than checking for (or ignoring) error codes -- or maybe even deal with a mixture (e.g., error code on end-of-file, exception on device not present, or vice-versa).
I can think of a few possible solutions:
1. An error handler for each class -- but this is hard to make changes specific to a certain instance, and also requires the handler to do any chaining. 2. An error handler for each class instance -- still requires the handler to do any chaining. 3. An error handler chain (e.g., vector <bool (MyClass::*)(error&)>) for each class -- hard to make changes specific to a certain instance. 4. An error handler chain for each class instance -- but this can require a lot of memory.
Any other ideas? Comments? -- David A. Cuthbert (henry.ece.cmu.edu!dacut) Graduate Student, Electrical and Computer Engineering Data Storage Systems Center, Carnegie Mellon University
[ Send an empty e-mail to c++-h...@netlab.cs.rpi.edu for info ] [ about comp.lang.c++.moderated. First time posters: do this! ]
> "Rock-a-bye function, on the call stack, > When you get called, there won't be a catch. > When a call throws, an exception will fall, > And down will come function, program, and all."
Tunes! [:-)
> There's been a lot of discussion about exceptions here, and the > consensus is that they should be thrown only in exceptional > conditions. Unfortunately, there seems to be little consensus as to > what "exceptional" really means.
IMHO, it means that if the code and hardware is working as expected, none should be thrown.
> Personally, I never use exceptions (too many paths of execution to > worry about, as seen in the latest Guru of the Week).
But you can use this argument in favor of exceptions too. For example, how would you report an error in evalutating something like this? e.First() + " " + e.Last();
> However, I > realize that people using my code might prefer to deal with them than > checking for (or ignoring) error codes -- or maybe even deal with a > mixture (e.g., error code on end-of-file, exception on device not > present, or vice-versa).
> I can think of a few possible solutions:
> 1. An error handler for each class -- but this is hard to make > changes specific to a certain instance, and also requires the > handler to do any chaining. > 2. An error handler for each class instance -- still requires the > handler to do any chaining. > 3. An error handler chain (e.g., vector <bool (MyClass::*)(error&)>) > for each class -- hard to make changes specific to a certain > instance. > 4. An error handler chain for each class instance -- but this can > require a lot of memory.
> Any other ideas? Comments?
IMHO, "too many paths" is not a sufficient reason to search for an alternative to exceptions. If errors truly are rare, I would rather not put in the extra effort to build in programmable error handlers into the classes I write. How often would it be that an exception thrown and caught is insufficient to recover from an error but that a programmable error handler is sufficient? -- Kevin J. Hopps, Imation. E-mail to: kjhopps-at-imation-dot-com My opinions are my own. I speak neither for Imation nor 3M. Support the anti-spam amendment, HR 1748. See http://www.cauce.org
[ Send an empty e-mail to c++-h...@netlab.cs.rpi.edu for info ] [ about comp.lang.c++.moderated. First time posters: do this! ]
da...@henry.ece.cmu.edu (David A. Cuthbert) writes:
|> Personally, I never use exceptions (too many paths of execution to |> worry about, as seen in the latest Guru of the Week). However, I |> realize that people using my code might prefer to deal with them than |> checking for (or ignoring) error codes -- or maybe even deal with a |> mixture (e.g., error code on end-of-file, exception on device not |> present, or vice-versa). |> |> I can think of a few possible solutions: |> |> 1. An error handler for each class -- but this is hard to make |> changes specific to a certain instance, and also requires the |> handler to do any chaining. |> 2. An error handler for each class instance -- still requires the |> handler to do any chaining. |> 3. An error handler chain (e.g., vector <bool (MyClass::*)(error&)>) |> for each class -- hard to make changes specific to a certain |> instance. |> 4. An error handler chain for each class instance -- but this can |> require a lot of memory.
My preference is for 2, but in the form of a call-back. The default call-back aborts with an error message, but the user can replace it with one which throws an exception, or returns. (The function calling the error handler will return whatever the error handler returns.)
More generally, I use a two level approach -- the default call-back for a class is a static variable which can be set by the user as well, so he can either change the global behavior of the class, or change the behavior on an instance by instance basis. Also, of course, the error handler is passes all necessary information about the error, so it might return in some cases, throw an exception in others, and abort in still others.
Finally, my error information class uses multiple inheritance in order to derive from a standard exception, or an exception derived from the standard class "exception", and still provide an extended interface, including "raise" (which just does a "throw *this") and "raiseStandard" (which throws the standard base class).
-- James Kanze +33 (0)1 39 23 84 71 mailto: ka...@gabi-soft.fr GABI Software, 22 rue Jacques-Lemercier, 78000 Versailles, France I'm looking for a job -- Je recherche du travail
[ Send an empty e-mail to c++-h...@netlab.cs.rpi.edu for info ] [ about comp.lang.c++.moderated. First time posters: do this! ]
{ I'm sure that it can be a civil presentation of views -jep }
[ ... clever little poem snipped ... ]
> There's been a lot of discussion about exceptions here, and the > consensus is that they should be thrown only in exceptional > conditions. Unfortunately, there seems to be little consensus as to > what "exceptional" really means.
Which really means we have no consensus at all...
> Personally, I never use exceptions (too many paths of execution to > worry about, as seen in the latest Guru of the Week). However, I > realize that people using my code might prefer to deal with them than > checking for (or ignoring) error codes -- or maybe even deal with a > mixture (e.g., error code on end-of-file, exception on device not > present, or vice-versa).
Actually, exceptions reduce the complexity of error handling when used properly. All the different exceptions that the Guru of the Week problem could have thrown could have been caught and dealt with at one point in the code. So all those error execution paths you're worried about can end up in one point.
Get ready for the jihad... -- Igor Siemienowicz Software Engineer, MICC Pty. Ltd. mailto:i...@micc.com.au http://www.micc.com.au
[ Send an empty e-mail to c++-h...@netlab.cs.rpi.edu for info ] [ about comp.lang.c++.moderated. First time posters: do this! ]
> Personally, I never use exceptions (too many paths of execution to > worry about, as seen in the latest Guru of the Week
I hear this alot, but I'm always puzzled by it. How do you avoid using exceptions?
If you don't use exceptions, constructors can't fail. So you can't dynamically allocate memory in the constructor. Now I understand you can use 2-phase construction to get around part of this, but how do you handle the copy constructor and assignment operators? Without these you can't pass an object by value (or return one by value). And you can't store these objects in STL collections.
I tried programming without exceptions once, and it felt like I was wearing a straightjacket. How do people deal with these issues?
-- Rich _____ Rich Ruh Flow Management Technologies rich....@flowmgt.com.no.spam.please
[ Send an empty e-mail to c++-h...@netlab.cs.rpi.edu for info ] [ about comp.lang.c++.moderated. First time posters: do this! ]
In article <606no6$...@netlab.cs.rpi.edu>, da...@henry.ece.cmu.edu (David A.
Cuthbert) writes:
|> There's been a lot of discussion about exceptions here, and the |> consensus is that they should be thrown only in exceptional |> conditions. Unfortunately, there seems to be little consensus as to |> what "exceptional" really means.
As in "not expected". Allthough that leaves open the discussion of whether e.g. syntax errors in the input of your program are "to be expected". Might even depend on whether the entity that generated the input is human or not...
|> Personally, I never use exceptions (too many paths of execution to |> worry about, as seen in the latest Guru of the Week).
If you really care about the potential problems, the number of paths will stay the same, because you need to handcode each and every one of them anyway. And the code gets a *lot* uglier too.
|> However, I |> realize that people using my code might prefer to deal with them than |> checking for (or ignoring) error codes -- or maybe even deal with a |> mixture (e.g., error code on end-of-file, exception on device not |> present, or vice-versa). |> |> I can think of a few possible solutions: |> |> 1. An error handler for each class -- but this is hard to make |> changes specific to a certain instance, and also requires the |> handler to do any chaining. |> 2. An error handler for each class instance -- still requires the |> handler to do any chaining. |> 3. An error handler chain (e.g., vector <bool (MyClass::*)(error&)>) |> for each class -- hard to make changes specific to a certain |> instance. |> 4. An error handler chain for each class instance -- but this can |> require a lot of memory. |> |> Any other ideas? Comments?
No other ideas, just a few comments:
+ You're making things even more difficult for the people you are trying to help. Remember: they want exceptions, so they will (or possibly: will have to) use them anyway. And now in addition to the standard stuff they have to deal with your mechanisms.
+ If you have callback functionality in your library, you get into part of the `Exceptions "through" non C++ functions' thread. What happens in your code if the callback throws? Hence, you have to think about exception safety anyway. But wait, it gets even worse: "even" something as simple as "new myclass(...)" can (and one day will) throw. So there simply is no way to escape from worrying about exceptions for anything but the simplest of programs.
Conclusion: stick to the language as it was intended, all resistance is futile. MCE -- ======================================================================== #include <std/disclaimer> Code of the Geeks v3.1 GCS d+ s+:- a31 C+++$ UHLUASO+++$ P+ L+++ E--- W++ N+++ !o K w--- !O M-- V-- PS+ PE+ Y+ PGP- t--- !5 !X R- tv- b+ DI++ D-- G++ e+++ h+(*) !r y? M. Eyckmans (MCE) eyckm...@imec.be ========================================================================
[ Send an empty e-mail to c++-h...@netlab.cs.rpi.edu for info ] [ about comp.lang.c++.moderated. First time posters: do this! ]
kjho...@mmm.com wrote in article <608h0e$...@netlab.cs.rpi.edu>...
> David A. Cuthbert wrote: > > There's been a lot of discussion about exceptions here, and the > > consensus is that they should be thrown only in exceptional > > conditions. Unfortunately, there seems to be little consensus as to > > what "exceptional" really means.
> IMHO, it means that if the code and hardware is working as expected, > none should be thrown.
Unfortunately, that's probably not a practical state of affairs to hope for.
Furthermore, there ARE situations where exceptions might be thrown even when all code and hardware is working correctly. There may simply not be enough resources for the program to run. When a resource allocation request fails, an exception is an appropriate response IMHO.
This applies even if the program's memory needs have been anticipated when choosing the hardware. What if a number of other processes are running at the same time?
-- Igor Siemienowicz Software Engineer, MICC Pty. Ltd. mailto:i...@micc.com.au http://www.micc.com.au
[ Send an empty e-mail to c++-h...@netlab.cs.rpi.edu for info ] [ about comp.lang.c++.moderated. First time posters: do this! ]
|> > Personally, I never use exceptions (too many paths of execution to |> > worry about, as seen in the latest Guru of the Week |> |> I hear this alot, but I'm always puzzled by it. How do you avoid using |> exceptions?
Lot's of ways. After all, it wasn't so long ago that most compilers didn't support exceptions.
|> If you don't use exceptions, constructors can't fail.
Sure they can. You just need a different way of reporting the error. And even with exceptions, you sometimes need a way, since constructors may fail in unexceptional ways.
|> So you can't |> dynamically allocate memory in the constructor.
Sure you can. Insufficient memory is a fatal error for many applications. IMHO, one should try and design the application so that it can be. For example, a server will only be responsible for serving the socket, and will hand off complicated commands to a new process. So insufficient memory in the new process will not crash the server.
Of course, conceptually, this is just a different type of exception. And while you can count on the OS to clean up part of the mess (partial exception safety), aborting a process without deleting any temporary files it is using will cause a real "memory" leak.
|> Now I understand you |> can |> use 2-phase construction to get around part of this, but how do you |> handle |> the copy constructor and assignment operators?
The most frequent solution I've seen has not been two phase construction, but defining an error state for the object -- failure in construction puts the object in the error state. (My experience also suggests that most complex objects don't support copy or assignment anyway.)
|> Without these you can't |> pass an object by value (or return one by value). And you can't store |> these objects in STL collections.
Most of the time, my STL collections contain smart pointers, and not the objects themselves. After all, if you pass or store by value, you lose polymorphism. Which means that in practice, you don't do it for anything more complex than an int or a string.
|> I tried programming without exceptions once, and it felt like I was |> wearing |> a straightjacket. How do people deal with these issues?
The same way we've always dealt with them.
-- James Kanze +33 (0)1 39 23 84 71 mailto: ka...@gabi-soft.fr GABI Software, 22 rue Jacques-Lemercier, 78000 Versailles, France I'm looking for a job -- Je recherche du travail
[ Send an empty e-mail to c++-h...@netlab.cs.rpi.edu for info ] [ about comp.lang.c++.moderated. First time posters: do this! ]
|> David A. Cuthbert wrote: |> > |> > "Rock-a-bye function, on the call stack, |> > When you get called, there won't be a catch. |> > When a call throws, an exception will fall, |> > And down will come function, program, and all." |> |> Tunes! [:-) |> |> > There's been a lot of discussion about exceptions here, and the |> > consensus is that they should be thrown only in exceptional |> > conditions. Unfortunately, there seems to be little consensus as to |> > what "exceptional" really means. |> |> IMHO, it means that if the code and hardware is working as expected, |> none should be thrown.
Excellent definition. I think that this more or less corresponds to what I spoke of in the thread on garbage collection, of the abstraction failing. (And I originally got the idea from an article by Nikolaus Wirth.)
I still hold that in most cases, the appropriate response for a failed abstraction is simply to abort the program. Of course, this is exactly what will happen if you ignore an exception, so one can say that it is currently the default behavior. And most cases != all. There are definitly programs which cannot be aborted, even when the abstaction fails. (Actually, I would argue this. While you may be able to trap an exception on insufficient memory, you can't on insufficient power. So the total system must *always* be able to survive an abort in the program.)
|> > Personally, I never use exceptions (too many paths of execution to |> > worry about, as seen in the latest Guru of the Week). |> |> But you can use this argument in favor of exceptions too. For example, |> how would you report an error in evalutating something like this? |> e.First() + " " + e.Last();
I fear that the latest GotW is somewhat misleading. If exceptions are allowed, but you are not allowed to know which functions can or cannot throw, then you cannot evaluate the correctness of a program. But then, evaluating correctness will also be impossible if return codes are used for reporting errors, but you are not allowed to know which functions may return error codes, and which ones return void.
The difference, of course, is elsewhere. You are required to specify whether a function returns an error code or a void in its declaration. If you declare a function to return void, and then try and return an error code, the compiler will complain, so you cannot "lie" about it. And the alternate program flowpaths are clearly visible, in the form of if statements. (The argument for exceptions is, of course, that the alternate flowpaths are TOO visible, and that by hiding the principle ones, they make the program less readable.)
|> > However, I |> > realize that people using my code might prefer to deal with them than |> > checking for (or ignoring) error codes -- or maybe even deal with a |> > mixture (e.g., error code on end-of-file, exception on device not |> > present, or vice-versa). |> > |> > I can think of a few possible solutions: |> > |> > 1. An error handler for each class -- but this is hard to make |> > changes specific to a certain instance, and also requires the |> > handler to do any chaining. |> > 2. An error handler for each class instance -- still requires the |> > handler to do any chaining. |> > 3. An error handler chain (e.g., vector <bool (MyClass::*)(error&)>) |> > for each class -- hard to make changes specific to a certain |> > instance. |> > 4. An error handler chain for each class instance -- but this can |> > require a lot of memory. |> > |> > Any other ideas? Comments? |> |> IMHO, "too many paths" is not a sufficient reason to search for an |> alternative to exceptions. If errors truly are rare, I would rather not |> put in the extra effort to build in programmable error handlers into the |> classes I write. How often would it be that an exception thrown and |> caught is insufficient to recover from an error but that a programmable |> error handler is sufficient?
I agree that "too many paths" is not a valid reason for rejecting exceptions. "Invisible paths" might be. "Lack of experience with the technology" definitly could be. (There's a chicken and egg problem with this one. How do you get experience with exceptions if you don't use them, because you lack experience. Well -- I write a lot of code which isn't production code, just to gain such experience.)
And of course, David's real point was: as a library author, how do you give the user a choice, rather than imposing your choice on him? A perfectly valid question, in my mind, regardless of whether you are for or against exceptions. (Although as Kevin has pointed out in earlier posts, the standard library, and most third party library vendors, will not be giving you this choice. Since the user must use exceptions anyway, regardless of what he thinks about them, it is difficult to argue for added complexity to give him a choice in your library.)
-- James Kanze +33 (0)1 39 23 84 71 mailto: ka...@gabi-soft.fr GABI Software, 22 rue Jacques-Lemercier, 78000 Versailles, France I'm looking for a job -- Je recherche du travail
[ Send an empty e-mail to c++-h...@netlab.cs.rpi.edu for info ] [ about comp.lang.c++.moderated. First time posters: do this! ]
Wow -- I didn't expect the discussion to go this way! Things are always interesting around here... :-)
Anyway, I didn't mean to discuss whether it is wise for me to use exceptions. I avoid them because I've gotten burned in the past: intolerably slow execution speed during the handling of an exception, having another fault/exception occur, and having the resulting beast come crashing down in a spectacular ball of flame. Ok, so this is a bit of an exaggeration. :-) Whether this is due to a poor implementation of exceptions in my platform or my lack of ability to code for exceptions is irrelevant: either prevents me from using them in my programs.
And, yes, I'll concede that exceptions are useful in constructors, etc. I didn't like checking for NULL returns on malloc(), etc., when I programmed in C, either. But to say that we can't live without exceptions is silliness. We got men on the moon without exceptions; OTOH, an (unhandled) exception is what killed the Ariane 5 mission.
Anyway let me give an example of the type of code I'm talking about:
TNetworkConnection connection; string response;
connection.ConnectTo("doppler.ece.cmu.edu", PNet_Telnet); // 1 connection.Send("This is a test"); // 2 response = connection.Receive(); // 3 connection.Close(); // 4
Ok, so let's say that someone spilled coffee into doppler and fried its network card -- it doesn't respond to the connection request on line 1. Is this an exceptional condition? (IMHO, no; this is comparable to file not found.)
What if the connection succeeds, but a power failure at doppler kills the connection during the receive on line 3? Is this exceptional? (again, IMHO no; ios doesn't throw if a sector on the disk is bad.)
But that's me, and someone who's a fan of exceptions could say that ios is poorly designed in this regard, both of these classes should be throwing exceptions, etc.; we'd argue all day, and neither of us would give an inch (or cm for the readers outside the US :-).
I think that locales and Unicode are good ideas and every program should make use of them -- even though I use English, write dates as mm/dd/yy, and tell time as hh:mm (am/pm) exclusively. Why should I force others to use my problem-reporting mechanisms (and why should I be forced to use others' such mechanisms) when I have a chance to be flexible?
Finally, I think I was a bit unclear when I said "error handler" (though it seems like few people actually made it that far though my article). I did mean a call-back function (which happens to handle errors) that has a default but can be easily overridden by the user. -- David A. Cuthbert (henry.ece.cmu.edu!dacut) Graduate Student, Electrical and Computer Engineering Data Storage Systems Center, Carnegie Mellon University
[ Send an empty e-mail to c++-h...@netlab.cs.rpi.edu for info ] [ about comp.lang.c++.moderated. First time posters: do this! ]
>consensus is that they should be thrown only in exceptional >conditions. Unfortunately, there seems to be little consensus as to >what "exceptional" really means.
>Personally, I never use exceptions (too many paths of execution to >worry about, as seen in the latest Guru of the Week). However, I >realize that people using my code might prefer to deal with them than >checking for (or ignoring) error codes -- or maybe even deal with a >mixture (e.g., error code on end-of-file, exception on device not >present, or vice-versa).
>I can think of a few possible solutions:
>1. An error handler for each class -- but this is hard to make > changes specific to a certain instance, and also requires the > handler to do any chaining. >2. An error handler for each class instance -- still requires the > handler to do any chaining. >3. An error handler chain (e.g., vector <bool (MyClass::*)(error&ly)>) > for each class -- hard to make changes specific to a certain > instance. >4. An error handler chain for each class instance -- but this can > require a lot of memory.
If you need an error handler, that sounds fairly exceptional. And exception handling is far simpler.
>Any other ideas? Comments?
How about conversion functions, like from string to number? If you pass a "hi mom" string to a conversion function, the easiest way to handle the error is to throw some sort of exception. Not an exceptional error, really, but still exceptions are best here.
I look at it like this: If a function can return a result that is either an error or a successful result, and if the caller can _always_ tell the difference, then you don't need exceptions. I prefer to do my own exception handling within the function if required, and return an appropriate error if one occurs. If a function can't return an unambiguous result, raise an exception. Period.
Glen
[ Send an empty e-mail to c++-h...@netlab.cs.rpi.edu for info ] [ about comp.lang.c++.moderated. First time posters: do this! ]
da...@henry.ece.cmu.edu (David A. Cuthbert) writes:
|> Anyway let me give an example of the type of code I'm talking about: |> |> TNetworkConnection connection; |> string response; |> |> connection.ConnectTo("doppler.ece.cmu.edu", PNet_Telnet); // 1 |> connection.Send("This is a test"); // 2 |> response = connection.Receive(); // 3 |> connection.Close(); // 4 |> |> Ok, so let's say that someone spilled coffee into doppler and fried |> its network card -- it doesn't respond to the connection request on |> line 1. Is this an exceptional condition? (IMHO, no; this is |> comparable to file not found.) |> |> What if the connection succeeds, but a power failure at doppler kills |> the connection during the receive on line 3? Is this exceptional? |> (again, IMHO no; ios doesn't throw if a sector on the disk is bad.)
Not strictly true: whether ios throws is under user control. Errors are defined in terms of "setting bits"; each bit is associated with an exception mask, and if the mask is set, an exception is thrown when the bit is set.
In this case, currently, compilers (or rather libraries) don't support this, because it is relatively new. More to the point, current implementations of iostream don't use exceptions because exceptions didn't exist when they were written, and implementors have been too busy writing the new parts of the library to worry about upgrading iostream.
In this particular case, in fact, I do not think it possible to have a quality implementation of iostream without using exceptions, whether you or I like it or not. (Personally, I don't like it.) The problem is that a bad sector on disk will be discovered in filebuf, and not istream, and the streambuf interface which filebuf implements has no way of reporting errors separately from EOF. So, on detection of a bad sector, filebuf has two possibilities: return EOF, or throw an exception. Returning EOF will basically cause ios::EOF to be set; if the current input required a character at this point, ios::fail will also be set. Which is, of course, the exact behavior of a normal EOF. On the other hand, the current draft requires the input functions to catch any exceptions generated during input, and set ios::badbit. So if filebuf chooses to report an error via an exception, the error can be recognized in user code as such, and not confused with normal EOF. In addition, if the user code has requested exceptions on badbit, the exception from filebuf will be rethrown, so the user code can potentially even know what type of error. (As far as I can tell, the type of the exception is implementation defined, so there is no way to do this in a portable manner.)
None of which is relevant to the initial thread, of course. IMHO (at least for most applications), a bad sector which causes a write error could definitly be considered exceptional. A broken connection during reception is more arguable -- it would depend on the application.
-- James Kanze +33 (0)1 39 23 84 71 mailto: ka...@gabi-soft.fr GABI Software, 22 rue Jacques-Lemercier, 78000 Versailles, France I'm looking for a job -- Je recherche du travail
[ Send an empty e-mail to c++-h...@netlab.cs.rpi.edu for info ] [ about comp.lang.c++.moderated. First time posters: do this! ]
In article <60gc0u$...@netlab.cs.rpi.edu>, "Glen Parker"
<glene...@techie.com> wrote: > >There's been a lot of discussion about exceptions here, and the >>consensus is that they should be thrown only in exceptional >>conditions. Unfortunately, there seems to be little consensus as to >>what "exceptional" really means. >If you need an error handler, that sounds fairly exceptional. And >exception handling is far simpler.
Here are a few opinins. Take them for what they are worth.
I find exceptions tremendously useful. I must admit, though, that they are useful only to the extent that programming discipline is used throughout the
program, much like return codes. For example, if only a few routines throw exceptions,and those routines fail rarely, then it is fairly easy to forget about them when coding, which can lead to interesting behavior. Further, if
someone adds exceptions to a library routine, few compilers will warn you.
For example, the following code is usually unwise in a program that throws exceptions, but is perfectly safe in a program that uses an error indicator variable like errno. (assuming the destructors do not do somethign bizzare in the event of errno being set...)
Blah * thing = new Blah; CoolFunction(); CoolFunction2(); delete thing;
If either CoolFunction 1 or 2 throws, then you just lost some memory. There
are perfectly reasonabl;e idioms, like auto ptrs, or a garbage collector, or
a host of other things, but the above code would go from working to broken if someone just decided that CoolFunction2 should throw an exception where it did not before.
I do like the Java idea that the exceptions thrown by a function are part of
the signature, and are checked. I am hopeful that this kind of discipline can be added to compilers. You are less likely to write the above if you claimed that the function threw some exceptions.
I use exceptions a lot, and they have cleaned up a lot of code for me. Generally, anything that indicates a serious problem in the code or the model I used for it throws an exception. I catch virtually all such, because exiting a program is rarely the "right" thing to do in many user interactive
environments. For example, if an estimator has died because of an off by one array index, I do not want the program to stop and the user to lose data, when they still have valid data in other areas of the program they might want to save.
Essentially, an exception means that someone has broken the contract in a likely recoverable way, but not certanly recoverable. For example, I assume
that running out of memory is an exceptional circumstance. In the environments I am writing code for, the program can get the memory it needs at virtually any point, but if it cannot, then it needs to rewind execution to the last reasonable point, and then warn the user. Nothing gets corrupted, and it is quite possible that they will want to continue with a smaller problem from the same point, so termiantion is not appropriate.
Things like a "file not found" error may or may not be exceptional, depending on whether this is something I considered "reasonable" in the program design. For one program I am working on, failure ot find certain files cannot be recovered from at the level of the file open routines. Thee are no backup plans which these can put in place to save the day, so an exception gets thrown, as the code after the open is not going to be needed.
Scott
Scott Ellsworth sc...@eviews.com "When a great many people are unable to find work, unemployment results" - Calvin Coolidge, (Stanley Walker, City Editor, p. 131 (1934)) "The barbarian is thwarted at the moat." - Scott Adams
[ Send an empty e-mail to c++-h...@netlab.cs.rpi.edu for info ] [ about comp.lang.c++.moderated. First time posters: do this! ]
Glen Parker <glene...@techie.com> wrote: >If you need an error handler, that sounds fairly exceptional. And >exception handling is far simpler.
Huh? Exception handling is much more visible than a handler and (on most implementations) incurs a horrid run-time penalty. This seems anything but simple to me.
A typical error handler is invisible (i.e., you don't bother to override the default). If you do, then the syntax is usually something akin to "myobject.SetErrorHandler(MyErrorHandler);" and nothing more.
Exceptions, on the other hand, seem to be the subject of many GotW topics -- full of not-so-visible flow control gotchas.
>If a function can't return an unambiguous result, raise an exception. >Period.
Far from "period." 0.2 + 0.8, on most machines, is ambiguous (0.999... or 1.0), yet I don't think an exception should be thrown.
Perhaps you have a nice environment for exception handling, but it causes noticeable delays on my system while being processed. I could not reasonably advise anyone to use them for normal program flow. -- David A. Cuthbert (henry.ece.cmu.edu!dacut) Graduate Student, Electrical and Computer Engineering Data Storage Systems Center, Carnegie Mellon University
[ Send an empty e-mail to c++-h...@netlab.cs.rpi.edu for info ] [ about comp.lang.c++.moderated. First time posters: do this! ]
Perhaps I am just being grumpy again, but one good source of information on how to use exceptions is code written in languages that have had exceptions in them from the start, and that do not have non-exception-using legacy code or obsolete-compiler compatibility problems.
Two examples that are easily accessed are the DEC-SRC Modula-3 sources, found at:
And, do remember that exceptions are just a tool, to be used as it amuses you. You can use them to make code faster, more readable, more robust, or any combination of the three.
People (like me) who have worked in the other languages mentioned find all the fuss a little puzzling. Note that in C++, the utility of exceptions is undercut by the default signature meaning "could throw anything", which makes it difficult for a compiler to meaningfully complain about the possibility of uncaught exceptions. We had this argument back in 1990, and the wrong (stupid, short-term, contrary to experimental results) choice was made. Both the languages mentioned above have compilers that whine (warning or error) when an exception is raised that is neither caught nor listed in the enclosing procedure/method's signature, and it is a big help in writing robust code in the first place and keeping it robust over time.
David Chase <ch...@world.std.com> wrote: >in C++, the utility of exceptions is undercut by the default >signature meaning "could throw anything" [...] >We had this argument back in 1990, and the wrong (stupid, >short-term, contrary to experimental results) choice was made.
Careful...
I wasn't on the committee when that choice was made, but one immediately obvious reason is that doing otherwise breaks just about every existing C and C++ program.
Current Network Technologies Corp. (http://www.cntc.com) 2695 North Sheridan Way, Suite 150, Mississauga ON Canada L5K 2N6 Tel 416-805-9088 Fax 905-822-3824
[ Send an empty e-mail to c++-h...@netlab.cs.rpi.edu for info ] [ about comp.lang.c++.moderated. First time posters: do this! ]
>David Chase <ch...@world.std.com> wrote: >>in C++, the utility of exceptions is undercut by the default >>signature meaning "could throw anything" [...] >>We had this argument back in 1990, and the wrong (stupid, >>short-term, contrary to experimental results) choice was made.
>I wasn't on the committee when that choice was made, but one immediately >obvious reason is that doing otherwise breaks just about every existing >C and C++ program.
Now I'm a bit confused...
I'm assuming that the discussion here is whether "void func();" should be the same as "void func() throw();" or "void func() throw(...);". Obviously, the committee chose the latter, while the former is arguably safer.
How would the "throw()" choice have broken nearly every program? I'm assuming that exceptions and exception specifiers were introduced at the same time -- please correct me if I'm wrong here. If exceptions were permitted before specifiers were around, then I can see how this would break a number of C++ programs, but not "just about every exisiting" program.
-- David A. Cuthbert (henry.ece.cmu.edu!dacut) Graduate Student, Electrical and Computer Engineering Data Storage Systems Center, Carnegie Mellon University
[ Send an empty e-mail to c++-h...@netlab.cs.rpi.edu for info ] [ about comp.lang.c++.moderated. First time posters: do this! ]
> How would the "throw()" choice have broken nearly every program? I'm > assuming that exceptions and exception specifiers were introduced at > the same time -- please correct me if I'm wrong here. If exceptions > were permitted before specifiers were around, then I can see how this > would break a number of C++ programs, but not "just about every > exisiting" program.
People's old C++ programs undoubtedly contain lots of functions that indirectly do things that may now throw exceptions (like allocate memory or do stream I/O). If the default exception spec was throw(), then the declarations of all these functions would have to be modified to say throw(...).
--
Ciao, Paul
(Please remove the extra "crud" from the return address, which has been altered to foil junk mail senders.)
[ Send an empty e-mail to c++-h...@netlab.cs.rpi.edu for info ] [ about comp.lang.c++.moderated. First time posters: do this! ]
David A. Cuthbert wrote: > How would the "throw()" choice have broken nearly every program? I'm > assuming that exceptions and exception specifiers were introduced at > the same time -- please correct me if I'm wrong here. If exceptions > were permitted before specifiers were around, then I can see how this > would break a number of C++ programs, but not "just about every > exisiting" program.
Yes, it would break just about every existing program.
Consider a C (style) function that calls a C++ function that may throw. If the C++ function throws, then the C function (which was written without thought of exceptions) naturally won't catch the exception, and therefore propagates it.
If the default exception specification were "throw()", it would break all C functions that directly or indirectly call something that might throw.
Current Network Technologies Corp. (http://www.cntc.com) 2695 North Sheridan Way, Suite 150, Mississauga ON Canada L5K 2N6 Tel 416-805-9088 Fax 905-822-3824
[ Send an empty e-mail to c++-h...@netlab.cs.rpi.edu for info ] [ about comp.lang.c++.moderated. First time posters: do this! ]
On 30 Sep 1997 18:11:28 -0400, Herb Sutter <He...@CNTC.com> wrote:
>David A. Cuthbert wrote: >> How would the "throw()" choice have broken nearly every program? >Consider a C (style) function that calls a C++ function that may >throw.
Isn't that function in trouble anyway? Might not be such a bad thing that it needs to be recompiled. I *want* exception guards around every C++ function that gets called by a C function.
Andrew Bell
[ Send an empty e-mail to c++-h...@netlab.cs.rpi.edu for info ] [ about comp.lang.c++.moderated. First time posters: do this! ]
|> David A. Cuthbert wrote: |> > How would the "throw()" choice have broken nearly every program? I'm |> > assuming that exceptions and exception specifiers were introduced at |> > the same time -- please correct me if I'm wrong here. If exceptions |> > were permitted before specifiers were around, then I can see how this |> > would break a number of C++ programs, but not "just about every |> > exisiting" program. |> |> Yes, it would break just about every existing program. |> |> Consider a C (style) function that calls a C++ function that may throw. |> If the C++ function throws, then the C function (which was written |> without thought of exceptions) naturally won't catch the exception, and |> therefore propagates it.
So how does the C function call the C++ function? The only way is through a pointer to function. (And I'm not sure that even that is guaranteed to work. I know of at least one compiler where C and C++ used a different stack layout for arguments.)
{Sorry... I meant a C style function that may well now be incorporated in a C++ program and compiled with a C++ compiler. The point was just that such legacy code wouldn't be exception-aware or -safe, and such code is pretty commonplace. -hps}
|> If the default exception specification were "throw()", it would break |> all C functions that directly or indirectly call something that might |> throw.
Which typically won't be very many. Only those which take a pointer to a function as an argument, or those which call through a global pointer to function.
-- James Kanze +33 (0)1 39 23 84 71 mailto: ka...@gabi-soft.fr GABI Software, 22 rue Jacques-Lemercier, 78000 Versailles, France I'm looking for a job -- Je recherche du travail
[ Send an empty e-mail to c++-h...@netlab.cs.rpi.edu for info ] [ about comp.lang.c++.moderated. First time posters: do this! ]
In article <606no6$...@netlab.cs.rpi.edu>, "David A. Cuthbert" <da...@henry.ece.cmu.edu> writes
>"Rock-a-bye function, on the call stack, > When you get called, there won't be a catch. > When a call throws, an exception will fall, > And down will come function, program, and all."
>There's been a lot of discussion about exceptions here, and the >consensus is that they should be thrown only in exceptional >conditions. Unfortunately, there seems to be little consensus as to >what "exceptional" really means.
I wonder what people think about using an exception in the way I have in a piece of code. I wouldn't say it was exceptional, because its a normal form of program termination, but as such it doesn't interfere with or slow down normal program execution flow. The code goes something like:
main() { try { do { User u = Login(); // throws UserGeneratedException is user // clicks cancel int rc = RestOfProgram(); } while (rc != EXITPROGRAM) } catch (UserGeneratedException) { // okay, bye bye return TRUE; } catch (...) { cout << "Whoops, dunno about that one" << endl; }
}
For me the point of the exception is that I wanted Login() to pass its class User return by value (or reference actually) not pointer, and I needed a way of signalling that the user has cancelled. The alternatives, as far as I can see, are using a User * return value and returning NULL, or like this but having a static member of User (User::nullUser) that returns a special instantiation that can be recognised by say User::IsNullUser(User u).
> In article <606no6$...@netlab.cs.rpi.edu>, "David A. Cuthbert" > <da...@henry.ece.cmu.edu> writes > >"Rock-a-bye function, on the call stack, > > When you get called, there won't be a catch. > > When a call throws, an exception will fall, > > And down will come function, program, and all."
> >There's been a lot of discussion about exceptions here, and the > >consensus is that they should be thrown only in exceptional > >conditions. Unfortunately, there seems to be little consensus as to > >what "exceptional" really means.
> I wonder what people think about using an exception in the way I have in > a piece of code. I wouldn't say it was exceptional, because its a normal > form of program termination, but as such it doesn't interfere with or > slow down normal program execution flow. The code goes something like:
Because nothing is ever ideal, exceptional conditions *are* normal :-)
> main() { > try { > do { > User u = Login(); // throws UserGeneratedException is user > // clicks cancel > int rc = RestOfProgram(); > } while (rc != EXITPROGRAM) > } > catch (UserGeneratedException) > { > // okay, bye bye > return TRUE; > } > catch (...) > { > cout << "Whoops, dunno about that one" << endl; > } > }
If Login() is interacting with a person, there is no way that an observer could tell whether you are throwing an exception or returning a status from it. Which one to use is an academic argument in this case.
The same would be true of RestOfProgram() too. Why did you choose to use a return code from that instead of an exception?
> For me the point of the exception is that I wanted Login() to pass its > class User return by value (or reference actually) not pointer, and I > needed a way of signalling that the user has cancelled. The > alternatives, as far as I can see, are using a User * return value and > returning NULL, or like this but having a static member of User > (User::nullUser) that returns a special instantiation that can be > recognised by say User::IsNullUser(User u).
You could also do it this way: User u; while (Login(u) && RestOfProgram() != EXITPROGRAM) continue; -- Kevin J. Hopps, Imation. E-mail to: kjhopps-at-imation-dot-com My opinions are my own. I speak neither for Imation nor 3M. Support the anti-spam amendment, HR 1748. See http://www.cauce.org
[ Send an empty e-mail to c++-h...@netlab.cs.rpi.edu for info ] [ about comp.lang.c++.moderated. First time posters: do this! ]
>I wonder what people think about using an exception in the way I have in >a piece of code. I wouldn't say it was exceptional, because its a normal >form of program termination, but as such it doesn't interfere with or >slow down normal program execution flow.
A similar thread ran back in February/March. Paul DeRocco wanted to use exceptions to handle MIDI message processing. (I reviewed this thread before posting my article on this thread; you can find it on Dejanews under the subject of "C++ exception overhead" on this group.)
To summarize, there was a consensus that exceptions tend to be inefficient; John Lilley found that using EH for normal flow processing (as compared to return values) was 50 times slower (MS VC++ 4.2 compiler, P166). There were two major camps on how exceptions should be used: "They're inefficient and will always be inefficient, so only use them in exceptional cases"; and "If they were [did you mean were NOT? --hlh] so darn inefficient, maybe we could use them in normal flow control."
There seems to be a circular problem here: because EH is slow, we only use it for exceptional cases. But since we only use it for exceptional cases, there's little reason to put any optimization effort into them. (Chicken-and-egg: what comes first, people using them for normal processing, or fast exceptions?)
>main() { > try { > do { > User u = Login(); // throws UserGeneratedException is user > // clicks cancel > int rc = RestOfProgram(); > } while (rc != EXITPROGRAM) > } > catch (UserGeneratedException) > { > // okay, bye bye > return TRUE; > } > catch (...) > { > cout << "Whoops, dunno about that one" << endl; > } >}
I have some surprisingly similar code for a telnet application that I wrote. It was a very convenient way to break out of a deeply nested function when a connection was broken. It's also painfully slow on an 8 MB machine upon disconnect (I suspect that the EH code is swapped out to disk). Keeping the code in memory (adding more memory) solved this problem.
But, then, it isn't used in a loop. An exception is thrown, my program cleans itself up, and exits.
>Comments? Criticisms? >From a purist point of view: "Boo, hiss!" (in jest, of course :-). >From a slightly more practical point of view: I don't see a problem
with it.
I recently had to write some Java code to parse boolean equations; the idea was to convert infix notataion to prefix notation, e.g., (2 + 3) * 5 / 8 => / * + 2 3 5 8. Unfortunately, the user can enter nonsensical expressions, e.g., (2 + 3 + ) * * ( 5 / 8. I thought of three ways to handle this: preprocess the expression for validity (quite difficult -- there are a lot of rules that are difficult to check for); make the infix expression object a zombie object and deal with some way of going back up a chain of recursion; or signal that the infix object couldn't achieve a self-consistent state by throwing an exception.
I opted for throwing the exception. From an aesthetic point of view, the code was quite elegant. It was probably slower than the second option, but (I'm guessing) faster than the first. Obviously, speed wasn't much of a concern (otherwise, I would have been coding in C++ and not interpreted Java).
As a result, I am beginning to rethink my stance on exceptions in general. -- David A. Cuthbert (henry.ece.cmu.edu!dacut) Graduate Student, Electrical and Computer Engineering Data Storage Systems Center, Carnegie Mellon University
[ Send an empty e-mail to c++-h...@netlab.cs.rpi.edu for info ] [ about comp.lang.c++.moderated. First time posters: do this! ]
>David A. Cuthbert wrote: >> How would the "throw()" choice have broken nearly every program? I'm >> assuming that exceptions and exception specifiers were introduced at >> the same time -- please correct me if I'm wrong here. >Yes, it would break just about every existing program.
>Consider a C (style) function that calls a C++ function that may throw.
My point was that an existing program wouldn't have thrown an exception since they didn't exist.
>If the default exception specification were "throw()", it would break >all C functions that directly or indirectly call something that might >throw.
It seems to me that the safer alternative is to have the default specification as throw() with the default behavior of unexpected() to rethrow the current exception rather than calling terminate().
Offhand, I can't think of any problems with this -- yeah, it makes the default behavior of unexpected() a little more dangerous, but anyone who is really careful with exceptions has probably changed unexpected() anyway -- but I'm sure that someone out there will point out something I've missed. :-)
-- David A. Cuthbert (henry.ece.cmu.edu!dacut) Graduate Student, Electrical and Computer Engineering Data Storage Systems Center, Carnegie Mellon University
[ Send an empty e-mail to c++-h...@netlab.cs.rpi.edu for info ] [ about comp.lang.c++.moderated. First time posters: do this! ]