There has a been a lot thats said about exceptions..all that good stuff.
All that bad stuff on another thread :-)
However one issue has typically been side-stepped. When is it a good idea to throw and when to return code ? Let me explain...
Primarily i feel the following are the main issues to undestand to make effective use of exceptions ..
1) How to write (exception safe/netural) code in the face of excetions 2) Exception catching and doing something about it before continuing 3) When should your function/method resorrt to throwing an exception 4) Change something and retry the operation ( maybe change seveal things, but one at a time and retry after each change)
The "Exceptional C++" series does a great job especially with issues 1 and 2. And almost nothing on part 3 or 4.
But the issue # 3 is really the first problem that needs to be understood to use exception for doing something about runtime errors in code. I havent seen this being discussed just as much as the other related issues. Even though i have seen an article or two titled something like "to throw or not to throw"
If you look at the standard library for in this matter... the strategies are like - Have two versions , one that throws and one that doesnt ( eg. at() , operator[] ) - Set some flag to enable or disable exceptions being called ( iostream library ) - Perhaps others that i havent noticed
It doesnt seem to be feasible to follow the first mechanism too often. Eventhough you give the calling code flexibility to choose or not choose
exceptions.
Given that you follow one of these strategies, does it imply it may be good idea to throw exceptions anywhere you would like to return an error code ? Uh... well that would create a a havoc since we often can/like ignore error codes but not exceptions....(ever checked returned code from printf ?)
Sidenote: If you are the "exceptions are a bitch" type person cause you think it creates more complex code look at this nice little experiment... http://www.shindich.com/sources/c++_topics/exceptions.html that contrasts code with and w/o exceptions. Unforutnately its title seem to suggest that it addresses the specfic question I ask here...but actually talks about more general issue of "are exceptions a good idea".
[ Send an empty e-mail to c++-h...@netlab.cs.rpi.edu for info ] [ about comp.lang.c++.moderated. First time posters: do this! ]
> 3) When should your function/method resorrt to throwing an exception > 4) Change something and retry the operation > ( maybe change seveal things, but one at a time and retry after > each change) [...]
> But the issue # 3 is really the first problem that needs to be > understood to use exception for doing something about runtime errors > in code. I havent seen this being discussed just as much as the > other related issues. Even though i have seen an article or two > titled something like "to throw or not to throw"
> If you look at the standard library for in this matter... the > strategies are like - Have two versions , one that throws and one > that doesnt ( eg. at() , operator[] ) - Set some flag to enable or > disable exceptions being called ( iostream library ) - Perhaps > others that i havent noticed
I suspect this was done because a lot of pre-exception code would have been broken, or at least bent, by the change to exceptions. For example, pre-exception code should do this:
int* i = new int[1000]; if (i == NULL) { ... handle error ...}
but post-exception code should do this:
try { int* i = new int[1000]; } catch (std::bad_alloc) { // I think that's how it's spelled! ... handle error ... {
so having two versions of parts of the standard library (one that throws, one that doesn't) was _probably_ an attempt to keep everyone happy, and not break too much code.
> Given that you follow one of these strategies, does it imply it may > be good idea to throw exceptions anywhere you would like to return > an error code ? Uh... well that would create a a havoc since we > often can/like ignore error codes but not exceptions....(ever > checked returned code from printf ?)
Well, IMHO we have several data points in favor of using exceptions:
1) Important parts of the standard library (i.e. 'new') throw exceptions by default
2) The C++ Gods (i.e. Stroustrup) think that they're absolutely necessary for correct error handling
3) Some kinds of errors can't be reported in any other way. For example, how do you return an error code if a constructor fails?
and we have IMHO one data point against them:
1) Writing exception-correct code is not trivial, and takes a certain amount of education.
I suppose we could add a second point here, that it's extremely difficult to graft exception safety onto code that wasn't built with it in mind.
My personal opinion is that I agree with the experts; I think it was Scott Meyers who wrote something to the effect of "Exceptions are difficult simply because correct error handling is difficult, and exceptions make it impossible to ignore the issue".
However, I also tend to not throw an exception if I can possibly help it. Sometimes there are simpler ways of signalling that a procedure failed.
-------------------------------------------------------------------------- Dave Steffen Wave after wave will flow with the tide Dept. of Physics And bury the world as it does Colorado State University Tide after tide will flow and recede steff...@lamar.colostate.edu Leaving life to go on as it was... - Peart / RUSH "The reason that our people suffer in this way.... is that our ancestors failed to rule wisely". -General Choi, Hong Hi
Apache Beta <apache-b...@cup.hp.com> wrote: > [Edited for brevity] > When should your function/method resorrt to throwing an exception?
> This is really the first problem that needs to be understood to use exception > for doing something about runtime errors in code.
You just answered your own question. Use exceptions for doing something about runtime errors in code. If it isn't an error, then don't throw an exception. If it is an error, then throw an exception. It really is that simple. The hard part is deciding what is, and isn't an error and no one can help you with that because only you know what the function in question is supposed to do, and what results are acceptable.
[ Send an empty e-mail to c++-h...@netlab.cs.rpi.edu for info ] [ about comp.lang.c++.moderated. First time posters: do this! ]
> However one issue has typically been side-stepped. When is it a > good idea to throw and when to return code ? Let me explain...
Never ever report any errors with return-values. It's that simple!
> If you look at the standard library for in this matter... the strategies > are like > - Have two versions , one that throws and one that doesnt ( eg. at() > , operator[] )
To understand this design decision it's important to see that passing an out of range index to operator[] is conceptually quite different from e.g. trying to open a file on a full disk. The former is a so-called program logic error, which could have been detected _before_ running the program. The latter is a problem than can only be detected at runtime. There is not much agreement on what should be done upon detection of a program logic error, mainly because of different safety requirements. For some programs (e.g. DVD-player) its perfectly legitimate to simply not detect the problem and continue with undefined behavior (and probably sooner or later fail with an access violation or the like), because such a failure will most probably not destroy data or harm anybody. Others should perform a _graceful_ emergency shut down followed by a system restart (e.g. life-supporting medical appliance), for obvious reasons.
> - Set some flag to enable or disable exceptions being called ( iostream > library )
Stream libraries were introduced before the dawn of exceptions. The non-EH behavior is only there for backward compatibility. Since most people agree that runtime errors should be reported with exceptions, I recommend to switch on the exceptions right after creating the stream object.
> Eventhough you give the calling code flexibility to choose or not choose > exceptions.
See above, don't do that. One problem with error-codes is that you can ignore them _without_a_trace_in_your_code_. To ignore exceptions you have to write a catch( /**/ ) {} handler which can be detected (and reviewed) easily with tools.
> Given that you follow one of these strategies, does it imply it may be > good idea to > throw exceptions anywhere you would like to return an error code ?
YES! That's exactly what exceptions were invented for! The huge benefit is that you don't have to write all that tedious passing-the-error-up-the-callchain code anymore. Simply throw the exception, document that fact and you're done. As errors tend to happen deep down burried at the 47th level of the call-stack and are typically not resolved (!=handled) until the stack has unwound to the 10th level, you can easily see how much boring "if (error) return error;"-coding exceptions save you from doing.
> Uh... well that would create a a havoc since we often can/like ignore > error codes > but not exceptions....(ever checked returned code from printf ?)
It's always better to leave the decisition to actively ignore an error to your clients.
HTH,
Andreas
[ Send an empty e-mail to c++-h...@netlab.cs.rpi.edu for info ] [ about comp.lang.c++.moderated. First time posters: do this! ]
> > However one issue has typically been side-stepped. When is it a good > > idea to throw and when to return code ? Let me explain... > Never ever report any errors with return-values. It's that simple!
So simple that no respeceted expert has made this recommendation to date. Exceptions aren't a silver bullet. Experts disagree as to when and where they should be used. But no one says that they are the only reasonable solution, regardless of the case.
> > If you look at the standard library for in this matter... the > > strategies are like > > - Have two versions , one that throws and one that doesnt ( eg. at() > > , operator[] ) > To understand this design decision it's important to see that passing > an out of range index to operator[] is conceptually quite different > from e.g. trying to open a file on a full disk. The former is a > so-called program logic error, which could have been detected _before_ > running the program. The latter is a problem than can only be > detected at runtime. There is not much agreement on what should be > done upon detection of a program logic error, mainly because of > different safety requirements. For some programs (e.g. DVD-player) its > perfectly legitimate to simply not detect the problem and continue > with undefined behavior (and probably sooner or later fail with an > access violation or the like), because such a failure will most > probably not destroy data or harm anybody. Others should perform a > _graceful_ emergency shut down followed by a system restart (e.g. > life-supporting medical appliance), for obvious reasons.
Letting a program stumble on after undefined behavior is never really an appropriate solution. If it happens, it is because we are human, and we make errors. Most of the time, the most appropriate action to take in case of an error is to abort with an error message -- this would be a very good implementation specific behavior for the undefined behavior in operator[]. A few, rare applications should try and recover. These should use at.
> > - Set some flag to enable or disable exceptions being called ( iostream > > library ) > Stream libraries were introduced before the dawn of exceptions. The > non-EH behavior is only there for backward compatibility. Since most > people agree that runtime errors should be reported with exceptions, I > recommend to switch on the exceptions right after creating the stream > object.
Operator new was also introduced before the dawn of exceptions. There is no non-EH behavior for backward compatibility. IO is a funny case; the default error reporting is probably the best solution most of the time, although there aren't very many other cases when such a strategy would be appropriate.
Exceptions might be appropriate for bad() in iostream. They might also be appropriate when reading temporary files which were written by the same program just before -- if you write 100 bytes, seek to the start, and a read of 100 bytes fails, there is probably something seriously wrong. But such cases aren't the rule.
> > Eventhough you give the calling code flexibility to choose or not > > choose exceptions. > See above, don't do that. One problem with error-codes is that you can > ignore them _without_a_trace_in_your_code_.
There are ways of avoiding that.
> To ignore exceptions you have to write a catch( /**/ ) {} handler > which can be detected (and reviewed) easily with tools. > > Given that you follow one of these strategies, does it imply it may > > be good idea to throw exceptions anywhere you would like to return > > an error code ? > YES! That's exactly what exceptions were invented for!
According to the author, exceptions were invented for exceptional cases. In practice, the general rule is that they are a good solution for errors in non critical code which almost certainly cannot be handled locally. Insufficient memory in new being the classical example:
- In short running programs, like a compiler, the best solution for insufficient memory is just to abort. If you can't compile his program, you can't compile it, and throwing an exception rather than aborting isn't going to help much here.
- In long running programs, like servers, insufficient memory can occur for two reasons: a memory leak (a programming error), or a request which was too complicated. In the second case, an exception, caught at the highest level, is an excellent way to abort the request. In the first case, the only way out is to abort and restart the program; since it is generally difficult to distinguish, if requests can have arbitrary complexity, you should probably go for the exception, and implement some sort of counter at the highest level -- if say 5 successive different requests fail because of lack of memory, you abort.
- In critical applications, you don't use dynamically allocated memory, so the problem doesn't occur:-).
- In some particular cases, it may be possible to recover locally from insufficient memory, say by reorganizing some memory or spilling data to disk. In such cases, you use new (nothrow), checking the return value for NULL.
The fact that the experts felt it necessary to provide a new which reports errors by return code says a lot.
> The huge benefit is that you don't have to write all that tedious > passing-the-error-up-the-callchain code anymore.
That is the only benefit. It's not a negligible benefit in cases where the error will be passed up a long chain. It's not a real benefit at all where the error will be treated immediately by the caller.
You use exceptions for exceptional cases, where there is no chance of local recovery. You use return codes in all other cases.
> Simply throw the exception, document that fact and you're done. As > errors tend to happen deep down burried at the 47th level of the > call-stack and are typically not resolved (!=handled) until the stack > has unwound to the 10th level, you can easily see how much boring "if > (error) return error;"-coding exceptions save you from doing.
We must encounter different types of errors. For the most part, with the exception of things like insufficient memory, I find myself handling errors one or two levels above where they occur.
> > Uh... well that would create a a havoc since we often can/like > > ignore error codes but not exceptions....(ever checked returned code > > from printf ?) > It's always better to leave the decisition to actively ignore an error > to your clients.
You don't have the choice. If the client wants to ignore the error, he will. If he wants to treat the error, he will.
-- James Kanze mailto:jka...@caicheuvreux.com Conseils en informatique orientée objet/ Beratung in objektorientierter Datenverarbeitung
[ Send an empty e-mail to c++-h...@netlab.cs.rpi.edu for info ] [ about comp.lang.c++.moderated. First time posters: do this! ]
Andreas Huber <spam2...@gmx.net> wrote: >> Uh... well that would create a a havoc since we often can/like >> ignore error codes >> but not exceptions....(ever checked returned code from printf ?)
> It's always better to leave the decisition to actively ignore an > error to your clients.
wchich means "do not catch exception thrown in your code, instead make client aware of the exception and let him handle the situation", and for this to work your code *must* be exception safe. Right ?
B.
[ Send an empty e-mail to c++-h...@netlab.cs.rpi.edu for info ] [ about comp.lang.c++.moderated. First time posters: do this! ]
> To understand this design decision it's important to see that passing an out > of range index to operator[] is conceptually quite different from e.g. > trying to open a file on a full disk. The former is a so-called program > logic error, which could have been detected _before_ running the program. > The latter is a problem than can only be detected at runtime.
Uh.. what makes you think operator[] for vector can be range-checked at compile time ? Thats really a outlandish expectation from any compiler given a dynamically resizable container. Do you know of any compiler that can do that ?
> Never ever report any errors with return-values. It's that simple!
..snip..
>>Given that you follow one of these strategies, does it imply it may be >>good idea to >>throw exceptions anywhere you would like to return an error code ?
> > YES! That's exactly what exceptions were invented for! The huge benefit is > that you don't have to write all that tedious > passing-the-error-up-the-callchain code anymore.
Your emphatic implication that exceptions were invented to totally replace traditional error handling techniques seems like your personal opinion unless Bjarne told you so.
Atleast in his book (TCPL), Bjarne doesnt seem to think the same. In Chapter 11 (special edtn) he implies that exception handling mechanism is more like an alternative than a replacement to traditional error handling techniques.....
To quote the text... "The exception handling mechanism provides an alternative to the traditional techniques when they are insufficient, inelegant and error prone"
--Roshan
[ Send an empty e-mail to c++-h...@netlab.cs.rpi.edu for info ] [ about comp.lang.c++.moderated. First time posters: do this! ]
news:Xns93227C7059079wrgrpde@130.133.1.4... > "Andreas Huber" <spam2...@gmx.net> wrote in > news:3e4c3a28$1@news.swissonline.ch: > > > It's always better to leave the decisition to actively ignore an error > > to your clients. > > Isn't that a point AGAINST using exceptions, since, when flagged > by an exception, an error can't be ignored by the client? >
Note the use of the phrase "actively ignore". The following code actively ignores any exceptions thrown by foo():
try { foo();
}
catch( ... ) { // ignore it
}
NeilB
[ Send an empty e-mail to c++-h...@netlab.cs.rpi.edu for info ] [ about comp.lang.c++.moderated. First time posters: do this! ]
> Isn't that a point AGAINST using exceptions, since, when flagged > by an exception, an error can't be ignored by the client?
I'm not sure I understand what your are saying, since ignoring an exception is quite easy:
try { // ...
}
catch ( ... ) {
}
The huge difference to error-codes is that the programmer must actively write this code and tools can easily detect that someone chooses to ignore an exception.
Regards,
Andreas
[ Send an empty e-mail to c++-h...@netlab.cs.rpi.edu for info ] [ about comp.lang.c++.moderated. First time posters: do this! ]
> > Never ever report any errors with return-values. It's that simple!
> So simple that no respeceted expert has made this recommendation to > date. Exceptions aren't a silver bullet. Experts disagree as to when > and where they should be used. But no one says that they are the only > reasonable solution, regardless of the case.
Ok, I knew this point will be coming from someone of the list regulars, and you are of course right. After a few projects where I have seen people fall back into the error-code return scheme for no apparent reason I tend to press this beyond of what is reasonable. Simply because it's easier to fix cases where people throw exceptions and should not than the other way round. BTW, in my last project (~0.25Mloc) there was not a single case where people should have used error-code returns rather than exceptions! I believe exceptions are the right choice for 99.9% of your everyday error-reporting needs.
> Letting a program stumble on after undefined behavior is never really an > appropriate solution. If it happens, it is because we are human, and we > make errors. Most of the time, the most appropriate action to take in > case of an error is to abort with an error message -- this would be a > very good implementation specific behavior for the undefined behavior in > operator[]. A few, rare applications should try and recover. These > should use at.
I don't see your point, as some applications simply cannot _afford_ to detect the argument to operator[] being out of bounds (in release mode of course).
> Operator new was also introduced before the dawn of exceptions. There > is no non-EH behavior for backward compatibility. IO is a funny case;
Yes there is: new (nothrow)
> the default error reporting is probably the best solution most of the > time, although there aren't very many other cases when such a strategy > would be appropriate.
> Exceptions might be appropriate for bad() in iostream. They might also > be appropriate when reading temporary files which were written by the > same program just before -- if you write 100 bytes, seek to the start, > and a read of 100 bytes fails, there is probably something seriously > wrong. But such cases aren't the rule.
Ok, I failed to say that I only turn on exceptions for eof in about half the cases. However, I use exceptions for fail and bad.
> > See above, don't do that. One problem with error-codes is that you can > > ignore them _without_a_trace_in_your_code_.
> There are ways of avoiding that.
Yep, there sure are ways. However, you still have to use exceptions for constructor failures which leaves you with two different approaches of error reporting. Unless there are very strong reasons not to do so, I tend to go for the KISS approach in such cases. That's why I recommend to use exceptions for all runtime-error reporting.
> According to the author, exceptions were invented for exceptional > cases. In practice, the general rule is that they are a good solution > for errors in non critical code which almost certainly cannot be handled > locally. Insufficient memory in new being the classical example:
> - In short running programs, like a compiler, the best solution for > insufficient memory is just to abort. If you can't compile his > program, you can't compile it, and throwing an exception rather than > aborting isn't going to help much here.
> - In long running programs, like servers, insufficient memory can > occur for two reasons: a memory leak (a programming error), or a > request which was too complicated. In the second case, an > exception, caught at the highest level, is an excellent way to abort > the request. In the first case, the only way out is to abort and > restart the program; since it is generally difficult to distinguish, > if requests can have arbitrary complexity, you should probably go > for the exception, and implement some sort of counter at the highest > level -- if say 5 successive different requests fail because of lack > of memory, you abort.
> - In critical applications, you don't use dynamically allocated > memory, so the problem doesn't occur:-).
> - In some particular cases, it may be possible to recover locally from > insufficient memory, say by reorganizing some memory or spilling > data to disk. In such cases, you use new (nothrow), checking the > return value for NULL.
I don't know the "official" rationale behind new (nothrow) and honestly I don't care that much because I can't think of any use for it (unless your platform or coding standard forbids you to use exceptions). In fact, all the cases you mentioned can just as well be handled with exceptions without any major disadvantages. 1) Are you saying that you would use new (nothrow) in short running programs? Why not use new and not handle the exception, this will automatically lead to abort() being called. 2) We agree ;-) 3) What do you mean with critical? Realtime? 4) I might not have as much experience as you do, but I have so far (8 years of C++ programming) not come across a single case where you could have handled an out of memory situation locally (right after calling new). Even if you could, why not use normal new and put a try-catch around it?
> The fact that the experts felt it necessary to provide a new which > reports errors by return code says a lot.
As mentioned above I don't know the rationale and I couldn't find one either but there are platforms that have until very recently not supported exception handling (WinCE). To be standards conformant, such platforms couldn't possibly support normal new but only new (nothrow). To me this is a far stronger case for having new (nothrow).
> That is the only benefit. It's not a negligible benefit in cases where > the error will be passed up a long chain. It's not a real benefit at > all where the error will be treated immediately by the caller.
How do you know that your immediate caller will be able to handle the error? IMO, there's no way to tell but I'd be very interested if you have come up with an _easy_ scheme that allows you to do so.
> You use exceptions for exceptional cases, where there is no chance of > local recovery. You use return codes in all other cases.
Again, how do you know who your caller is and what he does? Please give a simple rule to find out whether an error can be handled by your immediate caller or not. Honestly, even if such a rule existed I would still opt for the exception-only approach, for KISS reasons.
> We must encounter different types of errors. For the most part, with > the exception of things like insufficient memory, I find myself handling > errors one or two levels above where they occur.
This is contrary to my experience, please give an example.
> > > Uh... well that would create a a havoc since we often can/like > > > ignore error codes but not exceptions....(ever checked returned code > > > from printf ?) > > It's always better to leave the decisition to actively ignore an error > > to your clients.
> You don't have the choice. If the client wants to ignore the error, he > will. If he wants to treat the error, he will.
I was referring to the following: As long as you can't handle the runtime error locally you better inform your client instead of ignoring it and grinding on.
Regards,
Andreas
[ Send an empty e-mail to c++-h...@netlab.cs.rpi.edu for info ] [ about comp.lang.c++.moderated. First time posters: do this! ]
> > It's always better to leave the decisition to actively ignore an > > error to your clients.
> wchich means "do not catch exception thrown in your code, instead make > client aware of the exception and let him handle the situation", and for > this to work your code *must* be exception safe. Right ?
Yes, as long as there is no way for you to handle the error locally. Do not write any code that is not exception-safe!
Regards,
Andreas
[ 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 message <3e4e743...@news.swissonline.ch>, Andreas Huber <spam2...@gmx.net> writes
>I don't know the "official" rationale behind new (nothrow) and honestly I >don't care that much because I can't think of any use for it (unless your >platform or coding standard forbids you to use exceptions). In fact, all the >cases you mentioned can just as well be handled with exceptions without any >major disadvantages. >1) Are you saying that you would use new (nothrow) in short running >programs? Why not use new and not handle the exception, this will >automatically lead to abort() being called. >2) We agree ;-) >3) What do you mean with critical? Realtime? >4) I might not have as much experience as you do, but I have so far (8 years >of C++ programming) not come across a single case where you could have >handled an out of memory situation locally (right after calling new). Even >if you could, why not use normal new and put a try-catch around it?
The problem with using any form of new other than new(nothrow) is that the implementation just about has to put in all the exception handling mechanism (including calling abort for an unhandled exception). The problem is not with short running programs but in very long running programs in highly constrained resources where the very existence of exception handling mechanisms will make the program exceed the available resources. Typically this is in some forms of embedded programming. In highly competitive markets even pennies count and moving to larger resources is not a commercially acceptable solution.
No exception handling mechanism is probably irrelevant on PCs of all forms but it may be essential for programming the far commoner micro controllers that pervade our lives unseen and unconsidered even by many programmers.
-- ACCU Spring Conference 2003 April 2-5 The Conference you cannot afford to miss Check the details: http://www.accuconference.co.uk/ Francis Glassborow ACCU
[ 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 message <3e4e743...@news.swissonline.ch>, Andreas Huber <spam2...@gmx.net> writes
>Ok, I knew this point will be coming from someone of the list regulars, and >you are of course right. After a few projects where I have seen people fall >back into the error-code return scheme for no apparent reason I tend to >press this beyond of what is reasonable. Simply because it's easier to fix >cases where people throw exceptions and should not than the other way round. >BTW, in my last project (~0.25Mloc) there was not a single case where people >should have used error-code returns rather than exceptions! I believe >exceptions are the right choice for 99.9% of your everyday error-reporting >needs.
If that is true you are programming in a very special problem domain. The choice is not just between throwing an exception and an error code. There are other solutions that are relevant in other cases even new offers a more sophisticated set of choices.
-- ACCU Spring Conference 2003 April 2-5 The Conference you cannot afford to miss Check the details: http://www.accuconference.co.uk/ Francis Glassborow ACCU
[ Send an empty e-mail to c++-h...@netlab.cs.rpi.edu for info ] [ about comp.lang.c++.moderated. First time posters: do this! ]
"Roshan Naik" <roshan_n...@yahoo.com> wrote in message
news:EFh3a.285$l_5.245@news.cpqcorp.net... > > To understand this design decision it's important to see that passing an out > > of range index to operator[] is conceptually quite different from e.g. > > trying to open a file on a full disk. The former is a so-called program > > logic error, which could have been detected _before_ running the program. > > The latter is a problem than can only be detected at runtime. > > Uh.. what makes you think operator[] for vector can be range-checked at > compile time ? Thats really a outlandish expectation from any compiler > given a dynamically resizable container. Do you know of any compiler > that can do that ?
I didn't say that the compiler could have checked this. There are really two cases here: 1) The index depends on user input. In this case you'd better check for out of range situations before passing to operator[]. 2) The index only depends on calculations your program makes. Believe it or not, but in this case a sufficiently sophisticated static program analysis tool could have told you that the index will be out of range in certain cases. Such tools take your program sources as input and do _not_ run it while analysing. They come to that conclusion simply by analysing the outcome of _every_ branch your program makes. A human reviewer only reading your program could do the same.
> Your emphatic implication that exceptions were invented to totally > replace traditional error handling techniques seems like your personal > opinion unless Bjarne told you so.
Ok, the inventor of exceptions (AFAIK _not_ Bjarne Stroustrup) probably really did not want to completely replace the traditional way of error handling. But, see below...
> Atleast in his book (TCPL), Bjarne doesnt seem to think the same. In > Chapter 11 (special edtn) he implies that exception handling mechanism > is more like an alternative than a replacement to traditional error > handling techniques..... > > To quote the text... > "The exception handling mechanism provides an alternative to the > traditional techniques when they are insufficient, inelegant and error > prone"
I know that Bjarne has written stuff that is contrary to my views. However, a long time has passed since that book came out and compilers are much better at exception handling today than they used to be. Moreover, I claim that it is much simpler and safer to have one simple rule _everyone_ (rookies and seniors) in your project can follow rather than having to establish IMO very difficult to comprehend heuristics when to use exceptions and when not. In fact, I believe it's almost always a bad decision to return an error code. Please see my answer to James Kanze.
Regards,
Andreas
[ Send an empty e-mail to c++-h...@netlab.cs.rpi.edu for info ] [ about comp.lang.c++.moderated. First time posters: do this! ]
Usually I have a class what completely cover sertain problem domain and handle all errors within. It is expose some error flag or state, some class specific error code what signals is some special action should/can be done for recover, some general error code as returned by system and routine to generate error message what can use class information (name of file for file class for example). Methods of class returns only bool: are all right or not.
Using that methology with error codes is straightforward and with exceptions is cumbersome.
And next, usually error is spotted by service thread which nor can handle it nor has caller to propagate.
> Bronek, > > > > It's always better to leave the decisition to actively ignore an > > > error to your clients. > > > > wchich means "do not catch exception thrown in your code, instead make > > client aware of the exception and let him handle the situation", and for > > this to work your code *must* be exception safe. Right ? > > Yes, as long as there is no way for you to handle the error locally. Do not > write any code that is not exception-safe! [snip]
I hope you are thinking of the basic guarantee and not the strong. IMO, especially when dealing with 3rd party libs, the strong guarantee is too hard to provide in all but a few places.
[ 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 didn't say that the compiler could have checked this. There are really two > cases here: > 1) The index depends on user input. In this case you'd better check for out > of range situations before passing to operator[].
Why? Using at is simpler. In general, the class can detect error conditions much better than the code that invokes one of his functions.
Regards.
[ Send an empty e-mail to c++-h...@netlab.cs.rpi.edu for info ] [ about comp.lang.c++.moderated. First time posters: do this! ]
> The problem with using any form of new other than new(nothrow) is that > the implementation just about has to put in all the exception handling > mechanism (including calling abort for an unhandled exception). The > problem is not with short running programs but in very long running > programs in highly constrained resources where the very existence of > exception handling mechanisms will make the program exceed the available > resources. Typically this is in some forms of embedded programming. In > highly competitive markets even pennies count and moving to larger > resources is not a commercially acceptable solution.
I'm well aware of this and as I have already written in the answer to James' post, your environment could prohibit the use of exceptions. As outlined below, I believe this is only true for a very special type of applications.
> No exception handling mechanism is probably irrelevant on PCs of all > forms but it may be essential for programming the far commoner micro > controllers that pervade our lives unseen and unconsidered even by many > programmers.
I agree and I'm aware that there are programs which have to handle so few exceptional situations that only a small percentage of all functions could possibly fail with runtime errors (e.g. the software in a wristwatch that has all the bells and whistles but has no I/O apart from the buttons and the display). For such an application it could indeed be overkill to employ exceptions. However, I consider this a _very_ special type of programming environment, where also a few other well-established programming rules could be rendered impractical or even invalid.
For the rest (I believe the vast majority of all written lines of C++ code), the following thought experiment explains why exceptions are superior to error-code returns: Two programs are written for the same hardware. Both programs are _absolutely_identical_ in functionality but one makes full use of exceptions while the other has exceptions disabled and works with error code returns only. The type of functionality does not matter much, but let's assume that the programs must deal with quite a few different types of runtime errors (out-of-memory, I/O problems, etc.) Both implement "perfect" error handling, i.e. for all runtime errors that could possibly happen both programs have to try a remedy. I believe both programs should roughly be in the same league for executable size and runtime performance (on some platforms the program employing exceptions could even be _faster_ and _smaller_ but I won't go into details for now). Why? Well, consider how you have to write the program that does not use exception handling: After almost each and every function call you have to insert "if (error) return error;". Because in C++ one line of code often results in more than one function call (copy constructors, overloaded operators, etc.) you are forced to tear apart a lot of expressions. For example, the following results in 3 function calls for the expression z = .... alone and every single one could result in an exception being thrown (because all may allocate memory)!
matrix z, a, b, c; // fill a, b, c .... z = a * b * c;
Tearing appart all the expressions in your program in such a way and inserting all the necessary if (error) return error; statements is not only extremely tedious but also insanely error-prone. So error-prone, that it's almost impossible that the two programs could possibly behave identical in all situations (given that the programs are not toy examples but real-world applications). Moreover, as the return type is now occupied by the error-code you have to use reference parameters for the returned results. This leads to badly readable code for mathematical expressions. Last but not least, you always have to ask newly created objects whether they are useable as constructors cannot return error-codes.
To cut a long story short, I believe in a lot of cases programs employing traditional error-handling are only faster and smaller because they almost never reach the level of correctness of programs employing exceptions.
Regards,
Andreas
[ Send an empty e-mail to c++-h...@netlab.cs.rpi.edu for info ] [ about comp.lang.c++.moderated. First time posters: do this! ]
> >Ok, I knew this point will be coming from someone of the list
regulars, and
> >you are of course right. After a few projects where I have seen
people fall
> >back into the error-code return scheme for no apparent reason I tend to > >press this beyond of what is reasonable. Simply because it's easier
to fix
> >cases where people throw exceptions and should not than the other way round. > >BTW, in my last project (~0.25Mloc) there was not a single case where people > >should have used error-code returns rather than exceptions! I believe > >exceptions are the right choice for 99.9% of your everyday error-reporting > >needs.
> If that is true you are programming in a very special problem domain. > The choice is not just between throwing an exception and an error code. > There are other solutions that are relevant in other cases even new > offers a more sophisticated set of choices.
I don't follow. BTW, the project was the software for an ATM running on Win2000...
Regards,
Andreas
[ Send an empty e-mail to c++-h...@netlab.cs.rpi.edu for info ] [ about comp.lang.c++.moderated. First time posters: do this! ]
> Usually I have a class what completely cover sertain problem domain > and handle all errors within. It is expose some error flag or state, > some class specific error code what signals is some special action > should/can be done for recover, some general error code as returned by > system and routine to generate error message what can use class > information (name of file for file class for example). Methods of > class returns only bool: are all right or not.
> Using that methology with error codes is straightforward and with > exceptions is cumbersome.
Well, if you are absolutely sure that your immediate caller can handle _all_ runtime errors then returning an error code can indeed be an option. However, as I have explained in other posts, I believe this is a _very_ special situation and for the rest of your program you would most probably want to employ exceptions, so why complicate things with two types of error handling?
> And next, usually error is spotted by service thread which nor can > handle it nor has caller to propagate.
A thread has a sort of a caller, i.e. the other thread by which it was started. The other thread will at some point want to collect the results calculated by this thread and that's also where you could transmit your exception. I know this is not possible with normal (std) exceptions, but when you've had the foresight to give your exceptions a clone method, then transmitting to and rethrowing in the other thread works just fine.
Regards,
Andreas
[ 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 hope you are thinking of the basic guarantee and not the > strong. IMO, especially when dealing with 3rd party libs, the > strong guarantee is too hard to provide in all but a few places.
Yep, I had in mind _at_least_ the basic guarantee. Depending on your needs you might want to implement the strong guarantee, which is indeed harder in some cases...
Regards,
Andreas
[ 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 didn't say that the compiler could have checked this. There are > really two > > cases here: > > 1) The index depends on user input. In this case you'd better check > for out > > of range situations before passing to operator[].
> Why? Using at is simpler. In general, the class can detect error > conditions much better than the code that invokes one of his
functions.
You are of course right. What was I thinking? ;-)
Regards,
Andreas
[ Send an empty e-mail to c++-h...@netlab.cs.rpi.edu for info ] [ about comp.lang.c++.moderated. First time posters: do this! ]
> For the rest (I believe the vast majority of all written lines of C++ > code), the following thought experiment explains why exceptions are > superior to error-code returns: Two programs are written for the same > hardware. Both programs are _absolutely_identical_ in functionality > but one makes full use of exceptions while the other has exceptions > disabled and works with error code returns only. The type of > functionality does not matter much, but let's assume that the programs > must deal with quite a few different types of runtime errors > (out-of-memory, I/O problems, etc.)
What's in the etc.? What about a compiler, for example? Would you consider an error in the program being compiled an error? (I wouldn't; it's an expected situation. And I certainly wouldn't use exceptions to handle it.)
> Both implement "perfect" error handling, i.e. for all runtime errors > that could possibly happen both programs have to try a remedy. I > believe both programs should roughly be in the same league for > executable size and runtime performance (on some platforms the program > employing exceptions could even be _faster_ and _smaller_ but I won't > go into details for now). Why? Well, consider how you have to write > the program that does not use exception handling: After almost each > and every function call you have to insert "if (error) return > error;".
Nonsense. Only after function calls that can fail.
What do you do if you run out of memory. A lot of programs (compilers, etc.) should simple fail in such cases. For a lot of programs, the probability is so low, and the possibilities for recovery so poor, that failing is acceptable as well. Such programs replace the new handler, and so never see an std::bad_alloc. (With a lot of compilers, this has already been done for you:-(. And on some systems, like Linux, your program, or some program, will just crash.)
What is the probability of a write failing? It's pretty low on my machines, and it's perfectly acceptable to only test the results after the final close (which you have to do anyway, and you can't use an exception here anyway without wrapping it, since in case of other exceptions, it's likely to be called when unwinding the stack). And that's only one if in the entire program.
Things like opening a file should be tested and handled immediately, and the actual processing will never begin. No problem of propagating deeply here.
What types of errors are you thinking of that require if's all over the place?
> Because in C++ one line of code often results in more than one > function call (copy constructors, overloaded operators, etc.) you are > forced to tear apart a lot of expressions. For example, the following > results in 3 function calls for the expression z = .... alone and > every single one could result in an exception being thrown (because > all may allocate memory)! > matrix z, a, b, c; > // fill a, b, c .... > z = a * b * c;
I think that everyone is in agreement that in such trivial cases, new should throw if it doesn't abort the program. There are other solutions, however, and they don't necessarily result in more if statements being written. (We used them before exceptions existed.) The most usual is simply to mark the object as bad, and continue. A bit like NaN in IEEE floating point. A lot more if's get executed and the run-time is probably a little slower than with exceptions, but the code size is probably smaller. With exceptions, I need table entries for all of the call spots where an exception may propagate. If I use deferred error checking, like with non-signaling NaN's, the only place I need to check for an error is at the end of the expression.
> Tearing appart all the expressions in your program in such a way and > inserting all the necessary if (error) return error; statements is not > only extremely tedious but also insanely error-prone. So error-prone, > that it's almost impossible that the two programs could possibly > behave identical in all situations (given that the programs are not > toy examples but real-world applications). Moreover, as the return > type is now occupied by the error-code you have to use reference > parameters for the returned results. This leads to badly readable code > for mathematical expressions. Last but not least, you always have to > ask newly created objects whether they are useable as constructors > cannot return error-codes.
Interestingly, I've rarely seen mathematical code which uses signaling NaN's. I don't know whether it's because the mathematicians consider the code less clean with the asynchronous interuptions, or for some other reasons.
> To cut a long story short, I believe in a lot of cases programs > employing traditional error-handling are only faster and smaller > because they almost never reach the level of correctness of programs > employing exceptions.
My experience to date has been that programs employing exceptions are almost never correct, where as programs with return values often are. People like David Abraham have been making an enormous effort, both in developing new programming idioms and in educating people about them; it's largely a result of such efforts that I even consider exceptions. But if I look at most of the existing code at my client sites, there's still a lot to be done, especially with regards to education.
If you can afford to punt on insufficient memory, and abort, you can probably use all of the standard library without seeing a single exception. If you have a large existing code base that you have to live with, that's probably your only choice; code written five or more years ago is NOT exception safe. If you're doing a green fields project, exceptions are definitly worth considering for some times of errors, provided you can be sure that the people working on the project are up to date, and know how to program with them. I'd still avoid them for most run-of-the mill errors; exceptions are best when there aren't any try blocks, and if you have to handle the error at that call site, that means a try block for each call site.
-- James Kanze mailto:jka...@caicheuvreux.com Conseils en informatique orientée objet/ Beratung in objektorientierter Datenverarbeitung
[ Send an empty e-mail to c++-h...@netlab.cs.rpi.edu for info ] [ about comp.lang.c++.moderated. First time posters: do this! ]
> > > Never ever report any errors with return-values. It's that simple! > > So simple that no respeceted expert has made this recommendation to > > date. Exceptions aren't a silver bullet. Experts disagree as to > > when and where they should be used. But no one says that they are > > the only reasonable solution, regardless of the case. > Ok, I knew this point will be coming from someone of the list > regulars, and you are of course right. After a few projects where I > have seen people fall back into the error-code return scheme for no > apparent reason I tend to press this beyond of what is reasonable.
I've seen just the opposite. I've seen a lot of code written with that attitude that if you don't know what to do, throw an exception. There's obviously a middle road, but I've found that about 90% of the time, a return code is more appropriate than an exception.
Maybe that's just because I expect most errors, and don't consider them exceptional. Or that I'm use to thinking of error processing (detection, propagation and handling) as part of the algorithm. Or that I've noticed that most of the people throwing exceptions like wild don't have the foggiest notion as to what exception safety means (and have never heard of smart pointers, or RAII). This last problem is, of course, one of education. But it's one many of us still have to deal with.
> Simply because it's easier to fix cases where people throw exceptions > and should not than the other way round.
I'm not sure what you mean here. If the client code was written to use exceptions, it's going to silently ignore return values. If it was written to use return values, it likely won't compile with exceptions.
> BTW, in my last project (~0.25Mloc) there was not a single case where > people should have used error-code returns rather than exceptions!
You mean you never opened a file whose name was provided by the user.
> I believe exceptions are the right choice for 99.9% of your everyday > error-reporting needs.
I think it depends on the type of application. Most of my work is on large servers; exceptions are useful there for aborting requests without bringing the system down. But I can't think of anywhere in a compiler where they would be appropriate. And I'm sceptical about graphic clients, although I'll admit that my scepticism may be partially based on my negative experience with exceptions in Java.
> > Letting a program stumble on after undefined behavior is never > > really an appropriate solution. If it happens, it is because we are > > human, and we make errors. Most of the time, the most appropriate > > action to take in case of an error is to abort with an error message > > -- this would be a very good implementation specific behavior for > > the undefined behavior in operator[]. A few, rare applications > > should try and recover. These should use at. > I don't see your point, as some applications simply cannot _afford_ to > detect the argument to operator[] being out of bounds (in release mode > of course).
My point is that you shouldn't release code with an out of bounds operator[]. And if you are testing it (which is nice whenever you can afford it), the correct response is probably to abort, rather than to throw at an unexpected moment.
> > Operator new was also introduced before the dawn of exceptions. > > There is no non-EH behavior for backward compatibility. IO is a > > funny case; > Yes there is: new (nothrow)
How does that solve a backward compatibility problem?
> > the default error reporting is probably the best solution most of > > the time, although there aren't very many other cases when such a > > strategy would be appropriate. > > Exceptions might be appropriate for bad() in iostream. They might > > also be appropriate when reading temporary files which were written > > by the same program just before -- if you write 100 bytes, seek to > > the start, and a read of 100 bytes fails, there is probably > > something seriously wrong. But such cases aren't the rule. > Ok, I failed to say that I only turn on exceptions for eof in about > half the cases. However, I use exceptions for fail and bad.
I've never used an exception for eof. Nor for fail. I can see it for bad, in some cases. Generally speaking, however, it just doesn't seem worth the hassle.
> > > See above, don't do that. One problem with error-codes is that you > > > can ignore them _without_a_trace_in_your_code_. > > There are ways of avoiding that. > Yep, there sure are ways. However, you still have to use exceptions > for constructor failures which leaves you with two different > approaches of error reporting.
You always have to alternative of making constructors which can't fail. Generally, if something can fail, and the failure can be handled locally, I'd avoid doing it in a constructor.
> Unless there are very strong reasons not to do so, I tend to go for > the KISS approach in such cases. That's why I recommend to use > exceptions for all runtime-error reporting.
I'd say that KISS argues for using return codes everywhere:-).
> > According to the author, exceptions were invented for exceptional > > cases. In practice, the general rule is that they are a good > > solution for errors in non critical code which almost certainly > > cannot be handled locally. Insufficient memory in new being the > > classical example: > > - In short running programs, like a compiler, the best solution > > for insufficient memory is just to abort. If you can't compile > > his program, you can't compile it, and throwing an exception > > rather than aborting isn't going to help much here. > > - In long running programs, like servers, insufficient memory can > > occur for two reasons: a memory leak (a programming error), or a > > request which was too complicated. In the second case, an > > exception, caught at the highest level, is an excellent way to > > abort the request. In the first case, the only way out is to > > abort and restart the program; since it is generally difficult > > to distinguish, if requests can have arbitrary complexity, you > > should probably go for the exception, and implement some sort of > > counter at the highest level -- if say 5 successive different > > requests fail because of lack of memory, you abort. > > - In critical applications, you don't use dynamically allocated > > memory, so the problem doesn't occur:-). > > - In some particular cases, it may be possible to recover locally > > from insufficient memory, say by reorganizing some memory or > > spilling data to disk. In such cases, you use new (nothrow), > > checking the return value for NULL. > I don't know the "official" rationale behind new (nothrow) and > honestly I don't care that much because I can't think of any use for > it (unless your platform or coding standard forbids you to use > exceptions).
The official rational is that some people had code which was prepared to handle out of memory locally, at the point of the new, and that exceptions weren't appropriate for these cases. Since the cases are pretty much the exceptions, the default new throws, and you need a special form for the no throw version.
There are, of course, also cases where you simply cannot afford to throw. You certainly wouldn't want to use the normal new in a tracing mechanism (where it might be called during stack walkback due to another exception); you use new (nothrow), and if it fails, you fall back to unbuffered output, but you don't throw, whatever happens.
> In fact, all the cases you mentioned can just as well be handled with > exceptions without any major disadvantages. > 1) Are you saying that you would use new (nothrow) in short running > programs? Why not use new and not handle the exception, this will > automatically lead to abort() being called.
You don't want abort. You want to display a reasonable error message, and you don't want the core dump. The easiest solution is the one designed for this case: replace the new handler with one which does what you want.
> 2) We agree ;-) > 3) What do you mean with critical? Realtime?
Critical, like if the program fails, something bad happens. I've worked on things like locomotive brake systems, for example. Almost by definition, you can run out of a dynamic resource; whether you throw an exception, return NULL or abort in the new handler, the train is going to crash. And the railroads don't like that.
On large systems, the critical parts will usually be isolated on low level controls today, so that the main part of the control software can be written "normally".
> 4) I might not have as much experience as you do, but I have so far (8 > years of C++ programming) not come across a single case where you > could have handled an out of memory situation locally (right after > calling new). Even if you could, why not use normal new and put a > try-catch around it?
I've not run into them in my personal experience, but I know that they exist. An obvious example might be an editor -- when the call to new fails, it spills part of the file it is editing to disk, frees up the associated memory, and tries again. In general, I'd expect the case to occur in any system which has its own memory management, and only uses operator new to get the blocks it manages.
> > The fact that the experts felt it necessary to provide a new which > > reports errors by return code says a lot. > As mentioned above I don't know the rationale and I couldn't find one > either but there are platforms that have until very recently not > supported exception handling (WinCE). To be standards conformant, such > platforms couldn't possibly support normal new but only new > (nothrow). To me this is a far stronger case for having new (nothrow).