I searched this NG with deja
and read some GotW (http://www.peerdirect.com/resources/)
and some C++ tips (http://cpptips.hyperformix.com/Exceptions.html);
in particular http://cpptips.hyperformix.com/cpptips/except_consensus
was very informative.
But I'm afraid I still don't see if there is a consensus
whether or not
Exceptions are a Good Thing?
I found a lot of tips and discussion about the technicalities of
exceptions, but the big question is
From what I read, there seems to be a consensus that:
1. Writing exception-safe code is harder than without exceptions;
2. Excpetions introduce a second path of control flow "behind the scenes",
which increases the complexity of the code;
3. In order to do decent error-handling in constructors, you must use
exceptions.
So, my questions are:
a) should I use exceptions only for constructors and error codes for
all other methods?
b) if exceptions are used in general, should functions return *only*
error codes *or* throw exceptions? (i.e., is it ok to mix both in one
method?)
c) should exceptions be used only for "exceptional" cases, or could they
also be used for not-so-exceptional things, like bogus parameters passed
in from the caller?
All insights and pointers will be greatly appreciated.
TIA,
Gab.
--
/---------------------------------------------------------------------\
| Paradigm is a word too often used by those |
| who would like to have a new idea |
| but cannot think of one. |
| (Mervyn King, Deputy Governor, Bank of England) |
| |
| za...@igd.fhg.de g...@gab.cx Gabriel....@gmx.net |
| www.igd.fhg.de/~zach/ www.gab.cx __@/' |
\---------------------------------------------------------------------/
[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]
[ about comp.lang.c++.moderated. First time posters: do this! ]
However, I have found that many poorly designed class libraries use
them a lot. In this situation one has to catch the exceptions thrown
- MFC is a classic example of this..
The only case where they are indeed usefull is to prevent a critical
exception that may force program termination.. In this case its often
usefull to wrap the code with an exception then call your error handle
to notify the user and roll back to a stable state.
Andy
On 11 Dec 2000 14:19:48 -0500, za...@igd.fhg.de (Gabriel Zachmann)
wrote:
[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]
> 1. Writing exception-safe code is harder than without exceptions;
True. However, whether you like it or not, exceptions are in the
language and the WILL happen. The question is, will your code work
when they do happen?
> 2. Excpetions introduce a second path of control flow "behind the scenes",
> which increases the complexity of the code;
This path of control exiting "anywhere" already exists. Ignoring it
does not make it go away.
> 3. In order to do decent error-handling in constructors, you must use
> exceptions.
Yes, there is no other good way to indicate failure. Or, alternately,
design objects such that construction CAN'T fail. Then you don't have
to throw exceptions.
> So, my questions are:
> a) should I use exceptions only for constructors and error codes for
> all other methods?
Well, any exceptional situation where you know THAT an error occurred
but you don't know HOW to handle it is a good candidate for
exceptions.
I rarely throw them myself, but I try to write code that works if they
do happen to get thrown. This is because my code is a middleware
library, with user code calling into me, and I call back out into
them through callbacks. So they can throw exceptions and my code
really needs to continue working.
> b) if exceptions are used in general, should functions return *only*
> error codes *or* throw exceptions? (i.e., is it ok to mix both in one
> method?)
It's ok to mix, but have a consistent strategy. If your functions are
internal to a subsystem, it doesn't matter how they INTERNALLY handle
errors, and error codes are fine. (Your code knows about your other
code.) Exceptions are generally better for cross-subsystem kinds of
operations, where it is someone else's code that has to handle an
error you detect. Or, if your code is seperated enough to where you
don't want part of your code to know about error codes of another part
of your application.
> c) should exceptions be used only for "exceptional" cases, or could they
> also be used for not-so-exceptional things, like bogus parameters passed
> in from the caller?
Never use them for not-so-exceptional things that can be handled
better in other ways. Bogus parameters can indeed be VERY
exceptional, it all depends on the application.
I throw an exception when I know that I've detected misuse of some
code, especially if a user is doing it. If it's my own code misusing
other parts of my code, then it's simply a bug and the assert macro is
better at finding that.
--
Chris
http://people.ne.mediaone.net/abrahams/abrahams.html
http://www.octopull.demon.co.uk/c++/dragons/
> But I'm afraid I still don't see if there is a consensus
> whether or not
> Exceptions are a Good Thing?
>
> I found a lot of tips and discussion about the technicalities of
> exceptions, but the big question is
> From what I read, there seems to be a consensus that:
> 1. Writing exception-safe code is harder than without exceptions;
False. Writing exception safe code is easier than equivalent code
written using return codes and conditional branches (and setjmp &
longjmp).
What is true is that it requires a different coding style that many
developers are unaware of.
> 2. Excpetions introduce a second path of control flow "behind the
scenes",
One needs to think about program state not control paths. For example,
on exit from a function (either by return or exception) the destructors
of all auto variables will have been executed.
> which increases the complexity of the code;
When using error returns the need for multiple test & branches
introduces the same number of alternative paths. But they need to be
managed manually - which increases code complexity.
> 3. In order to do decent error-handling in constructors, you must use
> exceptions.
False. In the 1980's exceptions were not in the language and idioms
were developed to accomplish this. In particular "Two Phase
Construction" - the constructor didn't do anything that could fail, and
the client code was required to call an "init()" member function before
using the object.
Avoiding exceptions increases the complexity of both implementation and
client code - but does allow "decent error-handling".
> So, my questions are:
> a) should I use exceptions only for constructors and error codes for
> all other methods?
No, use exceptions for operations that:
/1/ may fail but are expected to work (e.g. allocating resources) and
/2/ are distant from "domain" code that reacts to the failure.
> b) if exceptions are used in general, should functions return *only*
> error codes *or* throw exceptions? (i.e., is it ok to mix both in
one
> method?)
It is OK to mix them.
> c) should exceptions be used only for "exceptional" cases, or could
they
> also be used for not-so-exceptional things, like bogus parameters
passed
> in from the caller?
This is an edge case:
/1/ Do you want to document and test that exceptions are thrown
for "bogus parameters"?
/2/ Do you want to specify valid parameters and leave the rest as
"undefined behaviour"?
Both are valid approaches depending on your context.
> All insights and pointers will be greatly appreciated.
HTH
--
Alan Griffiths http://www.octopull.demon.co.uk/
Senior Systems Consultant, Experian tel: +44 115 968 5118
Chair, Association of C and C++ Users http://accu.org/
Sent via Deja.com http://www.deja.com/
Before you buy.
> I am trying to decide whether or not to use exceptions.
> I searched this NG with deja
> and read some GotW (http://www.peerdirect.com/resources/)
> and some C++ tips (http://cpptips.hyperformix.com/Exceptions.html);
> in particular http://cpptips.hyperformix.com/cpptips/except_consensus
> was very informative.
> But I'm afraid I still don't see if there is a consensus
> whether or not
> Exceptions are a Good Thing?
There is no concensus. Some people swear by them. Others swear at
them.
> I found a lot of tips and discussion about the technicalities of
> exceptions, but the big question is
> From what I read, there seems to be a consensus that:
> 1. Writing exception-safe code is harder than without exceptions;
> 2. Excpetions introduce a second path of control flow "behind the scenes",
> which increases the complexity of the code;
> 3. In order to do decent error-handling in constructors, you must use
> exceptions.
Add overloaded operators to 3, and you've summarized it pretty well.
On the other hand, it's possible to design constructors so they don't
fail, or so that you can check them afterwards (a la iostream), so
it's not necessarily as big a point as is sometimes pretended.
And you missed:
4. Exceptions make the main body of the function simpler, so easier to
write and to understand.
I don't think there is one true answer. Generally, I'm fairly
sceptical of exceptions, but then, I'm sceptical of unproven solutions
in general. *IF* you have a lot of cases where error detection is at
a much lower level than error handling, exceptions can simplify the
intermediate code significantly. On the other hand, they do create a
whole new family of problems involving exception safety, and the make
rigorous analysis of code flow more difficult. Which aspect weighs
heaviest will vary according to the application and the organization.
Globally, I'd say that exceptions should not be used in a critical
application, where human life is at stake. And of course, in a lot of
simple applications (compilers, etc.), they're really irrelevant -- in
exceptional cases, you just abort with an error message. For typical
server applications, etc., however, they might have a place to abort
an operation without killing the process.
> So, my questions are:
> a) should I use exceptions only for constructors and error codes for
> all other methods?
No. Be consistent.
> b) if exceptions are used in general, should functions return *only*
> error codes *or* throw exceptions? (i.e., is it ok to mix both in one
> method?)
Ditto.
> c) should exceptions be used only for "exceptional" cases, or could they
> also be used for not-so-exceptional things, like bogus parameters passed
> in from the caller?
I would hope that a bogus parameter is something really exceptional,
if it comes from within my program. I wouldn't use exceptions for
errors in user input, however.
--
James Kanze mailto:ka...@gabi-soft.de
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
Ziegelhüttenweg 17a, 60598 Frankfurt, Germany Tel. +49(069)63198627
The only consensus of interest is then, IMO, the consensus of those
who'll maintain the code.
>...
> But I'm afraid I still don't see if there is a consensus
> whether or not
> Exceptions are a Good Thing?
>
Always depends on the application of the tool. Icepicks can
be great, although not a Good Thing as murder weapons. Of
course you mean as an error reporting mechanism, but even in
that context there's room for application and misapplication.
>...
> From what I read, there seems to be a consensus that:
> 1. Writing exception-safe code is harder than without exceptions;
Meaningless or false.
(1) If there can be no exceptions, then the code is exception-safe.
(2) Otherwise, you *need* exception handling in order to make the
code exception safe.
(3) With a more general interpretation, writing "error safe" code
is distinctly easier using exception handling (that's the
whole point of the mechanism).
> 2. Excpetions introduce a second path of control flow "behind the
scenes", which increases the complexity of the code;
First part is true, conclusion is generally false. Generally the
complexity of the code is lowered because you can separate error
handling from normal case code, and because you don't have to
clutter the code with return value checking. Otoh. it's *possible*
to increase the actual complexity of the code by lowering the
apparent complexity, e.g. code that is structured to function
correctly in the presence of exceptions but only because things
get done in a certain order, and where this isn't documented.
> 3. In order to do decent error-handling in constructors, you must
> use exceptions.
Generally this is false, but exceptions are way more convenient
for this than other means (e.g. two-phase construction with Init
method, reference error parameter or ditto global, error handling
function, whatever). What you do gain is automatic deallocation,
plus -- depending on the alternative considered -- removal of the
possibility of using a non-properly constructed object. These
advantages are so great that you'd need a very good reason *not*
to use exceptions for error reporting from constructors (one such
reason being the deallocation bug of Visual C++ 5.0 and earlier).
> ...
> a) should I use exceptions only for constructors and error codes for
> all other methods?
No. But that doesn't imply the opposite, that you should always use
exceptions. Use sound judgement, considering always how your classes
will or may be used. This call can be tough, since there is a
"conflict of interest" present. At the lowest levels of the code
where failures often occur, efficiency dictates return codes or some
such scheme, while correctness guarantees dictates using exceptions
(essentially this boils down to the guarantees you endowe your
methods with; one solution is to have one set of "bare" error-code
based functions and one set of "safe" exception-throwing wrappers).
> b) if exceptions are used in general, should functions return *only*
> error codes *or* throw exceptions? (i.e., is it ok to mix both in
> one method?)
Don't mix error reporting strategies. But you can use return codes
for success reporting. Again, this boils down to the contracts you
define for the methods, and designing those contracts can be hard.
> c) should exceptions be used only for "exceptional" cases, or could
> they also be used for not-so-exceptional things, like bogus
> parameters passed in from the caller?
First is easy: yes. Second part is false: bogus parameters *are* (or
at least, should be) exceptional. I'd use exceptions for that.
Hth.,
- Alf
--
alf_DOT_steinbach_AT_ac_DOT_com (clean the address before replying)
Sent via Deja.com http://www.deja.com/
Before you buy.
[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]
Don't think of exceptions as being error handling constructs; think of them
as program flow constructs. Just like a goto isn't automatically harmful or
beneficial in C, using exceptions isn't automatically good one way or
another in C++.
> 1. Writing exception-safe code is harder than without exceptions;
Untrue. Writing exceptionless code requires that you introduce
functionality to handle exceptional states. One way or another, exception
conditions occur and you'd better be equipped to handle them. If you don't
like how new throws an exception on a bad memory allocation, you're free to
use new(nothrow), but you'd better check for NULL after every allocation.
See what I mean? One way or another, error conditions must be checked for.
Exceptions are oftentimes an elegant way to check for, and handle, these
error states.
> 2. Excpetions introduce a second path of control flow "behind the scenes",
> which increases the complexity of the code;
No. They change a second path of control flow, not add a new one. The
original second path starts at an error state and leads straight to a
coredump. With error handling (which may include exceptions as part of an
intelligent error design), this catastrophic execution path can be
redirected to a more graceful exit, or even have termination avoided
altogether.
> 3. In order to do decent error-handling in constructors, you must use
> exceptions.
Not necessarily. Consider:
class A
{
public:
int errorstate;
A(void)
{
errorstate = 0;
// do more stuff here, traps an error
errorstate = 1; return;
// do more stuff here if no error trapped
}
};
int main(int argc, char *argv[])
{
A myfunc;
if (myfunc.errorstate) { // do error handling stuff here
}
Note that I don't recommend doing things this way. But it does show that
it's possible to do error handling in constructors without exceptions (even
if it means just flagging a failure appropriately).
> a) should I use exceptions only for constructors and error codes for
> all other methods?
Use them whenever they're appropriate. How will you know if they're
appropriate? By using your experience. So get out and experiment around
with exceptions some. :)
> b) if exceptions are used in general, should functions return *only*
> error codes *or* throw exceptions? (i.e., is it ok to mix both in one
> method?)
Just be consistent. If you do one, then only do that one. If you do both,
then always do both. Etc.
> c) should exceptions be used only for "exceptional" cases, or could they
> also be used for not-so-exceptional things, like bogus parameters
passed
> in from the caller?
Exceptions are not only useful for errors. Consider:
if (...)
{
if (...)
{
if (...)
{
if (...) throw myException();
// insert multiple closing brackets here
catch (myException &e)
{
.... etc.
}
.... In that above case, exceptions work as a better GOTO. Remember:
exceptions /are just program control statements/. They aren't magically
tied to error conditions.
a) no
b) no. Use error codes for run of the mill errors and exceptions for
catastrophic failures
c) I agree with the first part
Adrian
P.S Your sig is too long.
> za...@igd.fhg.de (Gabriel Zachmann) writes:
> > 1. Writing exception-safe code is harder than without exceptions;
> True. However, whether you like it or not, exceptions are in the
> language and the WILL happen. The question is, will your code work
> when they do happen?
That's not really true. The language supports exceptions, but it
certainly doesn't require their use. The standard library only throws
exceptions in a few specific cases, which it is possible to avoid.
> > 2. Excpetions introduce a second path of control flow "behind the scenes",
> > which increases the complexity of the code;
> This path of control exiting "anywhere" already exists. Ignoring it
> does not make it go away.
It doesn't exist in most of the code I write.
> > 3. In order to do decent error-handling in constructors, you must use
> > exceptions.
> Yes, there is no other good way to indicate failure. Or,
> alternately, design objects such that construction CAN'T fail. Then
> you don't have to throw exceptions.
Designing constructors so they can't fail is often a good idea anyway.
> > So, my questions are:
> > a) should I use exceptions only for constructors and error codes for
> > all other methods?
> Well, any exceptional situation where you know THAT an error occurred
> but you don't know HOW to handle it is a good candidate for
> exceptions.
> I rarely throw them myself, but I try to write code that works if
> they do happen to get thrown. This is because my code is a
> middleware library, with user code calling into me, and I call back
> out into them through callbacks. So they can throw exceptions and
> my code really needs to continue working.
In general, writing exception safe code is probably a good idea.
Because even if you don't use exceptions today, you might want to in
the future.
> > b) if exceptions are used in general, should functions return *only*
> > error codes *or* throw exceptions? (i.e., is it ok to mix both in one
> > method?)
> It's ok to mix, but have a consistent strategy. If your functions
> are internal to a subsystem, it doesn't matter how they INTERNALLY
> handle errors, and error codes are fine. (Your code knows about
> your other code.) Exceptions are generally better for
> cross-subsystem kinds of operations, where it is someone else's code
> that has to handle an error you detect. Or, if your code is
> seperated enough to where you don't want part of your code to know
> about error codes of another part of your application.
> > c) should exceptions be used only for "exceptional" cases, or could they
> > also be used for not-so-exceptional things, like bogus parameters
passed
> > in from the caller?
> Never use them for not-so-exceptional things that can be handled
> better in other ways. Bogus parameters can indeed be VERY
> exceptional, it all depends on the application.
> I throw an exception when I know that I've detected misuse of some
> code, especially if a user is doing it. If it's my own code
> misusing other parts of my code, then it's simply a bug and the
> assert macro is better at finding that.
It depends a lot on the application.
Ideally, you'd probably like to cut the application up into a lot of
little processes, so that an error in one (e.g. a bad pointer) can't
propagate back into the others. If you do this, you're "exception"
mechanism is called abort with an error message:-). In many cases,
however, the price for doing this is too high. So you use exceptions
for aborting what you'd really like to have in a separate process.
--
James Kanze mailto:ka...@gabi-soft.de
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
Ziegelhüttenweg 17a, 60598 Frankfurt, Germany Tel. +49(069)63198627
Interesting statement. Clearly, designing _anything_ so it can't fail is a good
idea. However, how does one manage this with constructors in particular? How
does one design a constructor so that it doesn't care if the machine is out of
memory, or if a needed file doesn't exist? The only answer is to push all that
off onto another function that the client has to call. But what does that buy?
I guess I'd like more explanation of your statement.
Even if you choose never to use exceptions yourself, I think it is
advisable to write exception safe code.
Francis Glassborow Association of C & C++ Users
64 Southfield Rd
Oxford OX4 1PA +44(0)1865 246490
All opinions are mine and do not represent those of any organisation
> "James Kanze" <James...@dresdner-bank.com> wrote in message
> news:3A3612BC...@dresdner-bank.com...
> >
> > Designing constructors so they can't fail is often a good idea anyway.
>
> Interesting statement. Clearly, designing _anything_ so it can't fail is a
good
> idea. However, how does one manage this with constructors in particular? How
> does one design a constructor so that it doesn't care if the machine is out
of
> memory, or if a needed file doesn't exist? The only answer is to push all
that
> off onto another function that the client has to call. But what does that
buy?
Easy.
Have the constructor do nothing.
Constructor()
{
}
Then have an Init() function that does the actual initialization.
You asked.
It buys a big plus in some situations, delayed activation. Sometimes
you are in situations where creation of temporaries is inevitable, for
example, sticking something into an STL collection. In those cases,
you like to have a lightweight constructor that doesn't actually do
anything, for example, a file object that doesn't actually open the
file, otherwise, even the creation of a temporary is going to open a
file, destruction of the temporary will close it. Very wasteful,
especially for disk access or network access. Imagine a
"SocketConnection" class that, for every temporary, had to actually go
out and contact the remote host.
Walt Howard
I think people should give a "no error code" program a try. Go all the
way. Never have your functions return error codes, always have them
throw an exception if they fail in their task. Really give exceptions
a fair shot.
Then, when you've made a program work that way, you can decide which
is really best, exceptions or error return codes. Until then, you are
really just guessing.
Walt Howard
Francis Glassborow <francis.g...@ntlworld.com> writes:
> In article <3A361160...@dresdner-bank.com>, James Kanze
> <James...@dresdner-bank.com> writes
> >Globally, I'd say that exceptions should not be used in a critical
> >application, where human life is at stake. And of course, in a lot of
> >simple applications (compilers, etc.), they're really irrelevant -- in
> >exceptional cases, you just abort with an error message. For typical
> >server applications, etc., however, they might have a place to abort
> >an operation without killing the process.
>
> Even if you choose never to use exceptions yourself, I think it is
> advisable to write exception safe code.
[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]
I'm learning COM right now. COM objects always return error codes. This in
itself was interesting; I'm not used to returning a result code from a function
that can only succeed, but it's nice and consistent.
The client of that COM object uses #import to call those COM methods. #import
sets things up so that if any method of the COM object fails, it throws an
exception. So COM clients (who use #import) must get used to the "all-exception"
approach.
I do like "all-exception", however, I'd point out that even "all-error codes" is
different than the way I'm used to programming.
> Easy.
>
> Have the constructor do nothing.
>
> Constructor()
> {
> }
> Then have an Init() function that does the actual initialization.
It's not always easy, only with trivial objects, or with objects that
hold objects that are guaranteed not to themselves throw exceptions.
Take your class above and make it have a data member (not a pointer)
of type Blow_Up and try to make a constructor that doesn't throw:
class Blow_Up
{
public:
Blow_Up() { throw 1; }
};
class A
{
public:
A()
{
// Q: how to implement such that construction doesn't fail?
}
private:
Blow_Up t;
};
--
Chris
I think the benefits of exceptions outweigh any complexities involved,
and exceptions should replace error codes in general (with, um, a
few "exceptions")
> b) if exceptions are used in general, should functions return *only*
> error codes *or* throw exceptions? (i.e., is it ok to mix both in
one
> method?)
It's OK to mix, but IMO not as a general strategy. You might decide to
do certain sets of conditions with return codes, and certain sets of
conditions with exceptions. See below.
> c) should exceptions be used only for "exceptional" cases, or could
they
> also be used for not-so-exceptional things, like bogus parameters
passed
> in from the caller?
It depends - how bad are bogus parameters? For example, if you can do
some reasonable default behavior if you get a bad parameter that
wouldn't surprise the use, then maybe no exception is needed. The
general guideline is to use exceptions when you cannot do, or finish,
what you were asked to do, and don't use exceptions to do more than
that.
--
Regards,
Jeff
Sent via Deja.com
http://www.deja.com/
[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]
Sorry, I was asking with respect to exceptions. I'm aware of other advantages
(and disadvantages) of this technique, but wanted to know how they relate to
constructor failure.
> > Designing constructors so they can't fail is often a good idea
> > anyway.
> Interesting statement. Clearly, designing _anything_ so it can't
> fail is a good idea. However, how does one manage this with
> constructors in particular? How does one design a constructor so
> that it doesn't care if the machine is out of memory, or if a needed
> file doesn't exist? The only answer is to push all that off onto
> another function that the client has to call. But what does that
> buy?
It means that you don't have to deal with exceptions coming from that
constructor. If you defer anything that can fail to a later
initialize function, you can handle a return code. If you use a
factory, you can delete the object if the initialization fails, and
return a null pointer. If on the other hand, you use an internal
failure flag, like iostream, you can integrate the error handling into
that of the normal case, again like iostream.
Globally, making it an absolute rule not to throw from a constructor
only makes sense (to me) if you are designing to not use exceptions
anywhere. But even in constructors, exceptions should only be used
for exceptional cases, so you will occasionally have cases where other
mechanisms are needed anyway.
--
James Kanze mailto:ka...@gabi-soft.de
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
Ziegelhüttenweg 17a, 60598 Frankfurt, Germany Tel. +49(069)63198627
What about a constructor like
struct X{
X() { try { Init(); /* ... */ } catch(...){} }
void Init() { /* ... */}
};
I am starting to respect exception safety more and more and am
reasoning about those problems either.
Ali
--
Albrecht Fritzsche, Software Developer
alfabet meta-modelling ag,
leibnitzstr. 53, 10629 berlin, germany
http://www.alfabet.de
> In article <slrn93a6ke...@schwind.igd.fhg.de>,
> za...@igd.fhg.de wrote:
> > From what I read, there seems to be a consensus that:
> > 1. Writing exception-safe code is harder than without exceptions;
> False. Writing exception safe code is easier than equivalent code
> written using return codes and conditional branches (and setjmp &
> longjmp).
It's certainly false that this is a consensus opinion. Whether
writing robust exception safe code is easier or is harder than the
alternatives is very much a personal matter. I've been writing robust
error handling code for over twenty years now, and I don't see where
exceptions make my life easier. But that could at least in part be
because I've ingrained habits which make the alternatives particularly
easy. Or it could be because I've mainly worked on critical systems,
where correct error handling is considered a fundamental part of the
basic algorithm (and the algorithms are generally fundamentally pretty
simple, so the added complexity due to error handling doesn't render
them unmanageable).
> What is true is that it requires a different coding style that many
> developers are unaware of.
> > 2. Excpetions introduce a second path of control flow "behind the
> scenes",
> One needs to think about program state not control paths. For
> example, on exit from a function (either by return or exception) the
> destructors of all auto variables will have been executed.
The problem is that there is very little theoretical work to support
program proofs based purely on program state, without regards to
control paths.
> > which increases the complexity of the code;
> When using error returns the need for multiple test & branches
> introduces the same number of alternative paths. But they need to
> be managed manually - which increases code complexity.
The number may actually be significantly less in practice. You always
know when a component returns a return code; you may often not know in
the case of exceptions, and you must be prepared to handle the worst
case.
> > 3. In order to do decent error-handling in constructors, you must use
> > exceptions.
> False. In the 1980's exceptions were not in the language and idioms
> were developed to accomplish this. In particular "Two Phase
> Construction" - the constructor didn't do anything that could fail,
> and the client code was required to call an "init()" member function
> before using the object.
> Avoiding exceptions increases the complexity of both implementation
> and client code - but does allow "decent error-handling".
> > So, my questions are:
> > a) should I use exceptions only for constructors and error codes for
> > all other methods?
> No, use exceptions for operations that:
> /1/ may fail but are expected to work (e.g. allocating resources) and
> /2/ are distant from "domain" code that reacts to the failure.
Right. Basically, if the error is such that you can recover and
continue, exceptions are probably not the correct answer. If the
error will almost certainly result in aborting the current operation,
then exceptions can be considered.
--
James Kanze mailto:ka...@gabi-soft.de
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
Ziegelhüttenweg 17a, 60598 Frankfurt, Germany Tel. +49(069)63198627
> Gabriel Zachmann wrote:
[snippage]
> > c) should exceptions be used only for "exceptional" cases, or
> > could they also be used for not-so-exceptional things, like
> > bogus parameters passed in from the caller?
>
> I would hope that a bogus parameter is something really exceptional,
> if it comes from within my program. I wouldn't use exceptions for
> errors in user input, however.
I would say that a bogus parameter is probably too exceptional to
handled by an exception.
The problem with throwing an exception when a programming error is
detected is that at some higher level, the exception may be caught
and then considered handled, while nothing has been done to fix the
error that caused the exception.
Rather then letting the program muddle on, I believe it is usually
better to have it log as much error information as possible and then
abort, leaving it up to whatever/whoever invoked it to take
appropriate action.
- Wil
--
Wil Evers, DOOSYS IT Consultants, Maarssen, Holland
[Wil underscore Evers at doosys dot com]
But I wouldn't regard this as an advantage, as I believe failures should be
handled via the exception mechanism.
> If you use a
> factory, you can delete the object if the initialization fails, and
> return a null pointer.
If the failure comes from the constructor, there is no need to delete the
object, of course.
> If on the other hand, you use an internal
> failure flag, like iostream, you can integrate the error handling into
> that of the normal case, again like iostream.
True...that's never especially appealed to me, though.
> Globally, making it an absolute rule not to throw from a constructor
> only makes sense (to me) if you are designing to not use exceptions
> anywhere.
Agreed.
But even in constructors, exceptions should only be used
> for exceptional cases, so you will occasionally have cases where other
> mechanisms are needed anyway.
Guess I'd have to see a specific case.
Repeat after me: It all depends on the program.
Every program will have different costs and benefits of "muddling on". If the
cost is low enough (the program can't do much harm--it's not guiding missiles or
anything) and/or the benefit is high enough (by not aborting, you at least give
the user the chance to save her work), then muddling on is appropriate.
This is a commonly-repeated (I used to say it too) but fuzzy statement. Its
main problem, borne out in many newsgroup discussions, is that what's "truly
exceptional" is subjective and hasn't so far been a reliable guide. Some
think it means hard errors where the system is going to crash anyway. Others
think it also includes serious errors where a major operation can't be
completed. Still others think it means when any operation, large or small,
can't be completed. A few people would even include "success with info"
warnings, meaning anything beyond "OK, done" would be an exception -- to
them, anything short of clear success is to them an "exceptional case."
So my question is: What does "exceptional cases" mean to you? Can you give a
clear and rigorous definition that can be used to make decisions about new
cases? If so, I can take the definition and apply it to some cases and see
whether or not I agree with it -- and, more importantly, why or why not.
Again, in fairness, I used to say the same thing, and after a several
muddled attempts over time I realized I was guilty of fuzzy thinking because
I couldn't decide on a clear and unambiguous definition.
I've finally come around to Dave Abrahams' view:
Exceptions are basically just glorified return codes
with different semantics,
the main semantic differences being that exceptions: a) can't be ignored; b)
don't have to be manually propagated up to a suitable handler; and c)
require some more care in intermediate code so that stack unwinding is safe.
The first two are clear advantages; the last is now (finally)
well-understood but does require extra coding discipline and will continue
to be a source of articles and talks and maybe even some new analysis about
cases not yet discovered/covered (although it's widely believed that the
area is indeed now sufficiently well covered to declare it "well-understood"
as I just did).
Let me float an idea and see what comes out: A lot of people lump the choice
of exceptions vs. return codes into the error handling strategy, but I think
it's useful to distinguish between the mechanism and the strategy. That is,
choices about error handling strategy (what errors to detect/report, and
what/where to correct them) could be orthogonal to the reporting method (the
middle piece, what mechanism to use to report them); together, both would
form the error handling policy. Comments? Reactions?
Herb
---
Herb Sutter (mailto:hsu...@peerdirect.com)
CTO, PeerDirect Inc. (http://www.peerdirect.com)
Contributing Editor, C/C++ Users Journal (http://www.cuj.com)
> Easy.
>
> Have the constructor do nothing.
>
> Constructor()
> {
> }
>
> Then have an Init() function that does the actual initialization.
>
> You asked.
>
> It buys a big plus in some situations, delayed activation...
But this idiom introduces a completely new kind of error -- attempts to access an
uninitialized object.
Does every member function test to make sure the object has been initialized?
That's a lot of clutter in the code. Or do you just allow the use of
uninitialized objects to eventually cause a crash?
Well, I guess that's another approach to this issue: Have Init() throw an
exception, which the constructor then ignores. :)
Sorry, I don't see how this would be a solution.
Not sure what Dave means by "different semantics". That's the trouble with
that
bloody word: what's the semantics of "semantics"? :)
In any case, return codes that indicate success clearly would not be replaced
by
exceptions.
> Does every member function test to make sure the object has been
initialized?
> That's a lot of clutter in the code.
It's not so bad. In my COM work (where two-stage init is required, at least as
far as I can see), I just have a macro (!) that checks the state and throws an
exception, if nec.--one line of code.
There are at least four ways of handling errors (exceptions).
1) Set a global variable and trust that it will be checked. I recently
asked a dozen attendees at on an Advanced C++ Development techniques
course to raise their hands if they had ever checked errno. I was
surprised that two actually claimed to have done so.
2) Use a handler - callback function - appropriate for a local fix and
immediate retry (e.g. out of memory, printer problems etc.)
3) Use some form of error return, useful if you expect that the calling
function can fix the problem, and if it does not, nothing terrible will
happen if it is ignored.
4) Throw an exception - useful if you expect that a possibly remote
function on the call stack will handle it. Also useful if the problem
must not be ignored.
Note that none of these classify problems as 'exceptional' just how they
are best handled. In general 2, 3 and 4 are useful. 1 can be used but
only if the error is non-fatal.
BTW I normally throw endofprogram (which I routinely catch in main() )
to ensure cleanup when ending anywhere other than in main()
Francis Glassborow Association of C & C++ Users
64 Southfield Rd
Oxford OX4 1PA +44(0)1865 246490
All opinions are mine and do not represent those of any organisation
[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]
>James Kanze <James...@dresdner-bank.com> writes:
>>exceptions should only be used for exceptional cases
>
>This is a commonly-repeated (I used to say it too) but fuzzy statement.
>
>So my question is: What does "exceptional cases" mean to you?
>
>Herb
In principle: an exception occurs when a function cannot satisfy its
stated or implied post-conditions even though the caller met its
pre-conditions.
In practice, this is to some extent circular, since the definition of
the post-conditions will depend on how errors are going to be reported.
Best wishes,
Matthew Collett
--
The word "reality" is generally used with the intention of evoking sentiment.
-- Arthur Eddington
Ditto, but in forcing myself to use exceptions I've had to create a
sharp razor criterium to decide, "use exceptions or not"? Right or
wrong, I've decided this:
For me, exception means, "that which the current context is not
prepared to deal with". That's pretty good but now and then I still
can't make the decision clearly. For example, a find() function. Is
failure to find what you are looking for, an exception? It
depends. The concept of "find" means you don't have it and might not
have it ever, otherwise you'd call it get(). If lots of failures are
reasonably expected as part of a normal run, it isn't. But, once
again, what do the words "reasonably" and "normal" mean?
By context I mostly mean function, but it can mean more. By this
definition, if you write an openfile function, and can't open the file
you have two choices: figure out how to fix the problem, right then
and there, or throw an exception.
When you code there is probably a main flow of control that you are
trying to accomplish, i.e., openfile, readwrite, closefile. If at any
point you are unable to proceed, that is an exception. Errors are like
the garbage in a program. When you are working furiously on a work of
art, for example a sculpture, you keep your attention on the creation,
on the intended result, not on the bits of clay that fall onto the
floor. Catch clauses are like the broom you use to sweep up the
garbage after your marvelous creation is done. In some ways, that
isn't a good analogy. In a computer program, some of the bits of clay
are fatal errors!
Why errorcodes suck.
1) your function must assume that the calling function understands its
error codes. If this is to happen your function, and the caller are
forever mutually dependent which lessens their generic use and
reuseabilty.
2) You can only return a small amount of information, usually a
number. This is often insufficient to correct the error. For example,
your fileopen function fails and returns an error 5, Access
denied. Great, no problema. Wouldn't it be nice to know which filename
failed? You say, "That's stupid! The calling function knows which
filename it used!". Are you sure? Maybe that's why the fileopen
failed, you weren't using the right filename to begin with. In fact
I'd be willing to be that 99% of failed opens are caused by wrong
filename.
3) error codes pervert the entire notion of a function. A strict
mathematical function is supposed to take input of certain parameters
and return only one value. We don't have to subscribe to strict math
just for the sake of it, but here is a consequence of that.
Code written using exceptions:
-----------------------------
String data = file.readline( DESIRED_LENGTH );
Code written without exceptions:
-------------------------------
String data;
char buffer[1024];
int rval = file.readline( buffer, sizeof(buffer));
if ( rval != error )
{
data = buffer;
return NO_ERROR;
}
else
return rval;
And so on. Even the function that called this has to check errorcodes!
The contamination spreads throughout the entire program. We've been
living for so long, accepting this as normal that few are questioning
it anymore. Error return codes are a hack!
7 times as many lines. Why? Because ideally, a function can be
inserted where a data item is wanted because it can be trusted to
return a value that fits the context. If you are using errorcodes, you
have to check to make sure the return value isn't the error value
before using it in the context.
You might say, "Yes, but at some point you must pay the piper and
catch those exceptions. Ha Ha! Where are you now Mr. Exception?"
Well I'd say, yes, I do, but errorcode handling requires paying the
piper anyway in every function. Using exceptions let's me deal with
the errors where I want to.
4) Error codes are left unchecked - This can be accidental on purpose,
or more likely, "so yeah, I got an error, what the hell do I do with
it now? I wrote this function to return a string, do I have to rewrite
the thing now? Screw it, I'll just print an error and abort, or just
log the error, or just ignore it altogether.
When I first tried exceptions I was skeptical but I forced myself to
do it and gradually, the light went on in my head. I did it because I
thought programmers around the world would be turning to this new
technology and I didn't want to become a dinosaur. I was wrong. Every
big shop I contracted in didn't use exceptions. I think this has three
main causes:
1) Intellectual Inertia. Programmers have each developed ways to code
that for them, are dependable and predictable. You need to really do
an entire program using only exceptions. In the Linux world, I've yet
to see an open source project that uses exceptions and darn few that
even use C++. So all the examples that are out there for new
programmers are using the old style error codes. You have to take it
upon yourself to give exceptions a try because it doesn't seem like
anyone else is going to do it. Programmers are the most suspicious
people in the world when it comes to new technologies. I'm sure that
behind that attitude is an incident of pure intellectual hell where
they tried something new and it ended up costing them evenings and
weekends debugging. I know that's what it is for me. Trying a new
technology, especially on an already overloaded workforce is
difficult.
2) The operating system and most programming libraries still use error
codes. So, wherever you interface to the OS you are forced to use
error codes. That probably won't change because those operating system
functions (APIs) need to be generic enough for many different
languages to use. And I don't see how they are going to completely
rewrite the operating system to use exceptions.
3) No consistent exception policy. The entire project should have at
least a good base class Exception object, and not the one provided by
the libraries. Use your own.
>
> I've finally come around to Dave Abrahams' view:
>
> Exceptions are basically just glorified return codes
> with different semantics,
>
Have him come on here and discuss it with us.
> the main semantic differences being that exceptions: a) can't be ignored; b)
> don't have to be manually propagated up to a suitable handler; and c)
> require some more care in intermediate code so that stack unwinding is safe.
> The first two are clear advantages; the last is now (finally)
> well-understood but does require extra coding discipline and will continue
> to be a source of articles and talks and maybe even some new analysis about
> cases not yet discovered/covered (although it's widely believed that the
> area is indeed now sufficiently well covered to declare it "well-understood"
> as I just did).
You left out a big one: Exceptions can return any type of object, and all the
error-information you need.
>
> Let me float an idea and see what comes out: A lot of people lump the choice
> of exceptions vs. return codes into the error handling strategy, but I think
> it's useful to distinguish between the mechanism and the strategy. That is,
> choices about error handling strategy (what errors to detect/report, and
> what/where to correct them) could be orthogonal to the reporting method (the
> middle piece, what mechanism to use to report them); together, both would
> form the error handling policy. Comments? Reactions?
>
I'm not sure what you mean. But I think you are promoting
exceptions. You see, exceptions promote orthogonality. Throwers of a
proper Exception class (based in a common base class) don't have to be
concerned about side effects as far as compiling and linking
go. Returners of error codes need to know what the calling function is
expecting as a return value. Not very orthogonal.
Of course, I could be completely wrong about all of the above. :)
I have to get back to work now.
Walt Howard
>James Kanze <James...@dresdner-bank.com> writes:
>>exceptions should only be used for exceptional cases
>
>This is a commonly-repeated (I used to say it too) but fuzzy statement. Its
>main problem, borne out in many newsgroup discussions, is that what's "truly
>exceptional" is subjective and hasn't so far been a reliable guide. Some
>think it means hard errors where the system is going to crash anyway. Others
>think it also includes serious errors where a major operation can't be
>completed. Still others think it means when any operation, large or small,
>can't be completed.
>A few people would even include "success with info"
>warnings, meaning anything beyond "OK, done" would be an exception -- to
>them, anything short of clear success is to them an "exceptional case."
I guess this approach would be true if one was coding from the Use
Case. In there it is common for a normal flow to be documented and
exceptions to the rule to also be documented. If one was developing
using this idiom then I guess exceptions would fit.
Andy
>But I'm afraid I still don't see if there is a consensus
>whether or not
> Exceptions are a Good Thing?
By now, you've probably found out that it is a matter of choosing
a programming style. But the C++ libraries are geared towards
leveraging exceptions, and the RAII idiom (resource acquisition
is initialization). When considering the use of exceptions in C++,
make sure you understand RAII first: it is essential for exceptions
to be usable, and invites you to use exceptions in constructors.
Being able to create the objects=resources that you will use
is a first step towards being able to accomplis a task.
Then you call functions to perform operations using the resources.
If it is normally expected that the operations will succeed, you
do not need to bother handling error codes.
If an unexpected error occurs at any point, only some top-level
handler needs to bother handling it (e.g. display a diagnostic
message to the user).
>I found a lot of tips and discussion about the technicalities of
>exceptions, but the big question is
> From what I read, there seems to be a consensus that:
>1. Writing exception-safe code is harder than without exceptions;
There are mostly style issues that one has to be careful with.
>2. Excpetions introduce a second path of control flow "behind the scenes",
> which increases the complexity of the code;
Not true in my perspective: using exceptions keeps you from having
to bother with error handling in many situations: no need to test
for error codes, no need to check if malloc returned zero, etc...
Error handling is only needed in the parts of the code where
errors are actually corrected.
However, this comes at the cost of having to obey some style rules.
The logic is different from most procedural languages, and often
seen as complicated.
>3. In order to do decent error-handling in constructors, you must use
> exceptions.
Yes. RAII and exceptions work hand in hand.
>So, my questions are:
>a) should I use exceptions only for constructors and error codes for
> all other methods?
No, be consistent. I would recommend using exceptions.
Many useful C++ library functions and objects (e.g. containers) will
throw exceptions anyway.
Note that some prefer taking the opposite approach (have 'do nothing'
constructors, and then a separate initialization function which
returns an error code) - which you'll find in some popular libraries
(such as MFC). I find that those are a pain to use ...
>b) if exceptions are used in general, should functions return *only*
> error codes *or* throw exceptions? (i.e., is it ok to mix both in one
> method?)
Again, it is important to remain consistent.
>c) should exceptions be used only for "exceptional" cases, or could they
> also be used for not-so-exceptional things, like bogus parameters passed
> in from the caller?
As others, I would think that bogus parameters is usually a programming
error, and is therefore intended to be exceptional.
But if a failure is expected to be common, do not hesitate to return
a status code. Also remember that you can provide two versions of the
same function: one that throws an exception for users that do not want
to bother with error handling (or expect that no error shall occur),
and one that returns a success code (e.g. a bool) for users that expect
that the operation is likely to fail.
A good criterion is that you should only have few try{}catch(...)
blocks in your application. If there are many, then maybe:
- you should create RAII classes, or use existing ones (auto_ptr and
all the containers for example).
- you are using exceptions when a return code would be better.
I hope that this perspective will help,
Ivan
--
Ivan Vecerina - Surgical Navigation Network
--
Brainbench MVP for C++
http://www.brainbench.com
In EPOC you are forced to use two-phase construction all the time, because
their wonky setjmp/longjmp "exception" mechanism doesn't call destructors
when you throw. The way they get round it is simply to make a factory
function for everything, like this
class CThing : public CBase{
public:
static CThing* NewLC(){
CThing* self = new CThing();
CleanupStack::PushL(self);
self->ConstructL();
return self;
}
private:
CThing(); // can't throw
ConstructL(); // does the things that throw
};
(Anything on the CleanupStack gets deleted if you throw, and inheriting from
CBase zeros the memory, so deleting what is in effect a half constructed
object is more likely to work)
You could change this to use return values I suppose.
Note that using this idiom means that any class with initialisation stuff
that might go wrong cannot be instantiated on the stack. This breaks most
RIIA stuff you might want to do. It makes your code slower. It means you
have to type in all that stuff repeatedly. It may also give you boils.
You missed out
d) are more expensive when the exception is "often" thrown.
but I agree that a+b are a Good Thing. Your c is a discipline that
most of us are still absorbing into our sub-consciousness, but at
least the ground rules are now known.
> ... choices about error handling strategy (what errors to detect/report,
> and what/where to correct them) could be orthogonal to the reporting
> method (the middle piece, what mechanism to use to report them);
> together, both would form the error handling policy. Comments? Reactions?
I'm not sure what you mean by error handling policy. Can you define
it without reference to the two orthogonal considerations you've just
mentioned?
I agree that return codes and exceptions are just mechanisms, and I
can think of three reasons to choose one or other.
1) Performance: The "error" is sufficiently common that exceptions
are too expensive, or sufficiently uncommon that checking return
codes is too expensive. Of course, our estimate of how often
it will fail depends on our assumptions about use. The classic
example is opening files. Failing to open our own executable image
is surely unexpected, but failure to open a file when our user
had to type in a long path name by hand is surely the expected case.
2) Verbosity: "try {stuff();} catch (xyz) {fix();}" is more typing
than "if (!stuff()) fix()" for certain values of stuff and fix.
If the "error" is unlikely to be handled or even inspected by its
immediate caller, then your point b favours the use of exceptions.
RAII can be used to reduce this likelihood by automating the
rollback that intervening layers need to perform, but I don't
think this is possible in every case, and it is itself a source
of verbosity, so it merely alters the arithmetic. It doesn't
provide a killer argument in favour of exceptions in every case.
3) The environment demands one or the other. Some functions in C++
have to use exceptions to indicate an error, and some functions
have to use return codes because of compatibililty with non-C++
code. This is obviously a killer argument for these functions, but
can also influence the previous two reasons in the case of functions
that are likely to be called indirectly from such an environment.
Some embedded programmers (no, I don't mean that literally) might
use this to justify a blanket ban on exceptions and using functions
that throw them.
Indeed, I would advance these as the only rational basis for making the
choice, in a sort of "please don't toast me I was only thinking aloud"
kind of way.
> "James Kanze" <James...@dresdner-bank.com> wrote in message
> news:3A376900...@dresdner-bank.com...
> > [An Init method] It means that you don't have to deal with
> > exceptions coming from that constructor. If you defer anything
> > that can fail to a later initialize function, you can handle a
> > return code.
> But I wouldn't regard this as an advantage, as I believe failures
> should be handled via the exception mechanism.
Consider my answer in context. At one point, it was suggested that
you should only use exceptions from the constructor; in other cases,
use return codes. All I'm pointing out here is that if exceptions are
"bad" (for whatever reason), then they are equally bad from
constructors, and that there are ways to handle errors.
If you are using exceptions, of course, there is no reason not to use
them in the constructor. Supposing a modern compiler; I know of some
compilers, in the past, that wouldn't free the memory if the
constructor in a new expression failed because of an exception.
> > If you use a factory, you can delete the object if the
> > initialization fails, and return a null pointer.
> If the failure comes from the constructor, there is no need to
> delete the object, of course.
If the failure is signaled by an exception, and the compiler is
standards conforming in this regard. I've used compilers without
exceptions, and worse, I've used compilers with exceptions, but which
didn't delete the memory correctly. (I don't think that this is a
problem with any current releases, but be warned if you have to use an
older compiler.)
> > If on the other hand, you use an internal
> > failure flag, like iostream, you can integrate the error handling into
> > that of the normal case, again like iostream.
> True...that's never especially appealed to me, though.
Actually, in the ofstream case, at least, I find it very nice, most of
the time. I can just ignore the error, and check it once at the end,
when I close the file. (Note that the error will typically not occur
immediately when I write the character, but only when the ofstream
flushes to disk. So it is deferred anyway.)
On the other hand, that doesn't cover errors for things like open.
There, I will check the results immediately, since "cannot open xxx"
is a distinctly different type of error than "write error on xxx".
> > Globally, making it an absolute rule not to throw from a
> > constructor only makes sense (to me) if you are designing to not
> > use exceptions anywhere.
> Agreed.
> > But even in constructors, exceptions should only be used for
> > exceptional cases, so you will occasionally have cases where other
> > mechanisms are needed anyway.
> Guess I'd have to see a specific case.
Just about every case is specific, in some way. I don't like using
exceptions for errors on user input, for example. In a real sense,
these aren't "errors"; your reaction should be part of your standard
behavior.
--
James Kanze mailto:ka...@gabi-soft.de
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
Ziegelhüttenweg 17a, 60598 Frankfurt, Germany Tel. +49(069)63198627
void* operator new( size_t bytes )
{
static void* reserve = malloc( 40000 );
void* p = malloc( bytes);
if ( !p )
{
MessageBox( NULL, "You are running out of memory", "WARNING", NULL );
free(reserve);
p = malloc(bytes);
}
return p;
}
void operator delete( void* ptr )
{
free( ptr );
}
Walt Howard
Albrecht Fritzsche <albrecht....@alfabet.de> writes:
> Mark Wilden wrote:
> >
> > However, how does one manage this with constructors in particular?
> > How does one design a constructor so that it doesn't care if the
> > machine is out of memory, or if a needed file doesn't exist?
>
> What about a constructor like
>
> struct X{
> X() { try { Init(); /* ... */ } catch(...){} }
> void Init() { /* ... */}
> };
>
> I am starting to respect exception safety more and more and am
> reasoning about those problems either.
[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]
> James Kanze <James...@dresdner-bank.com> writes:
> >exceptions should only be used for exceptional cases
> This is a commonly-repeated (I used to say it too) but fuzzy
> statement. Its main problem, borne out in many newsgroup
> discussions, is that what's "truly exceptional" is subjective and
> hasn't so far been a reliable guide. Some think it means hard errors
> where the system is going to crash anyway. Others think it also
> includes serious errors where a major operation can't be
> completed. Still others think it means when any operation, large or
> small, can't be completed. A few people would even include "success
> with info" warnings, meaning anything beyond "OK, done" would be an
> exception -- to them, anything short of clear success is to them an
> "exceptional case."
Agreed. For some software, the "exceptional" case would be that it
actually worked:-).
> So my question is: What does "exceptional cases" mean to you? Can
> you give a clear and rigorous definition that can be used to make
> decisions about new cases? If so, I can take the definition and
> apply it to some cases and see whether or not I agree with it --
> and, more importantly, why or why not. Again, in fairness, I used
> to say the same thing, and after a several muddled attempts over
> time I realized I was guilty of fuzzy thinking because I couldn't
> decide on a clear and unambiguous definition.
I cannot really give a precise definition either. I just said it
because everybody says it. My own criteria are somewhat different,
but perhaps too restrictive for most people: use exceptions when the
only reasonable action is to abort, otherwise, return codes. And when
in doubt, use a return code; the user can always wrap it to throw an
exception, with little additional overhead. (The reverse is much more
expensive.)
> I've finally come around to Dave Abrahams' view:
> Exceptions are basically just glorified return codes
> with different semantics,
Which, of course, depends on what you mean by return codes. There's
certainly a difference between exceptions and the return value of
sin(double) (and I don't think that even Dave would recommend that sin
use an exception to return its result). If by return codes, you mean
only error reporting mechanisms, then yes. Exceptions are an error
reporting mechanism.
> the main semantic differences being that exceptions: a) can't be
> ignored;
But that's true of my ReturnCode class.
> b) don't have to be manually propagated up to a suitable
> handler; and c) require some more care in intermediate code so that
> stack unwinding is safe.
The advantage and the disadvantage.
> The first two are clear advantages; the
> last is now (finally) well-understood
By you, Dave, and perhaps a few readers of this newsgroup. From what
I've seen, I'd guess that this is only true for about 1% or 2% of the
programmers, however.
> but does require extra coding
> discipline and will continue to be a source of articles and talks
> and maybe even some new analysis about cases not yet
> discovered/covered (although it's widely believed that the area is
> indeed now sufficiently well covered to declare it "well-understood"
> as I just did).
There are two aspects to "well understood". The problem is certainly
well understood. Some solutions are known, but I wouldn't say that
globally, the solutions are well understood. And again, I'm only
talking about people who regularly read this newsgroup -- globally, my
impression is that most programmers aren't even aware that there is a
problem to understand.
> Let me float an idea and see what comes out: A lot of people lump
> the choice of exceptions vs. return codes into the error handling
> strategy, but I think it's useful to distinguish between the
> mechanism and the strategy. That is, choices about error handling
> strategy (what errors to detect/report, and what/where to correct
> them) could be orthogonal to the reporting method (the middle piece,
> what mechanism to use to report them); together, both would form the
> error handling policy. Comments? Reactions?
I've often posted that exceptions are only a implementation mechanism
for transmitting errors; their use (or not) doesn't affect the design
of error handling in general. IMHO, there are three aspects to error
handling in general: detection, reporting and handling. Exceptions
are irrelevant for the first and the last, and in many ways, just an
implementation detail with regards to the second: they concern the
how, but not the what.
In this regard, I find that most people ask the question, exceptions
or not, way to soon. How can you decide on the merits of an
implementation detail if you don't know what you want to implement?
The other point I've noticed, and this still seems to be true, despite
Dave's constant lecturing to the contrary, is that most people tend to
think of exception safety, when they think of it at all, in terms of
memory leaks, or at the most, resource management, and not in terms of
total program coherence. If resource management were the only
concern, exception safety would be trivial.
--
James Kanze mailto:ka...@gabi-soft.de
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
Ziegelhüttenweg 17a, 60598 Frankfurt, Germany Tel. +49(069)63198627
> Walt Howard wrote:
>
> > Easy.
> >
> > Have the constructor do nothing.
> >
> > Constructor()
> > {
> > }
> >
> > Then have an Init() function that does the actual initialization.
> >
> > You asked.
> >
> > It buys a big plus in some situations, delayed activation...
>
> But this idiom introduces a completely new kind of error -- attempts to
access an
> uninitialized object.
> Does every member function test to make sure the object has been
initialized?
> That's a lot of clutter in the code. Or do you just allow the use of
> uninitialized objects to eventually cause a crash?
Yes. Every member function can do it.
if ( !Initialized )
Initialize();
Woop dee doo.
I'm afraid there are situations where you have no choice but to delay
activation. The object is still constructed properly. It won't cause a
crash to use it. It's just not fully operational yet. Like a socket
object that isn't connected yet. Trying to write to it will just get
you an error or exception, not a crash.
Walt Howard
So can return values.
Francis Glassborow Association of C & C++ Users
64 Southfield Rd
Oxford OX4 1PA +44(0)1865 246490
All opinions are mine and do not represent those of any organisation
[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]
> "Kevin Cline" <kcl...@mayannetworks.com> wrote in message
> news:3A37BF13...@mayannetworks.com...
>
> > Does every member function test to make sure the object has been
> initialized?
> > That's a lot of clutter in the code.
>
> It's not so bad. In my COM work (where two-stage init is required, at least as
> far as I can see), I just have a macro (!) that checks the state and throws an
> exception, if nec.--one line of code.
Why would you use a macro instead of an inline function call?
class X {
private:
inline init_test() { if (!initialized) throw unitialized; }
>Herb Sutter <hsu...@peerdirect.com> wrote:
>
>>James Kanze <James...@dresdner-bank.com> writes:
>>>exceptions should only be used for exceptional cases
>>
>>This is a commonly-repeated (I used to say it too) but fuzzy statement.
>>
>>So my question is: What does "exceptional cases" mean to you?
>
>In principle: an exception occurs when a function cannot satisfy its
>stated or implied post-conditions even though the caller met its
>pre-conditions.
OK, I'll bite: Does that include warnings and success-with-info? Also, how
should other problems (such as parameter and precondition errors) be
reported?
>In practice, this is to some extent circular, since the definition of
>the post-conditions will depend on how errors are going to be reported.
Herb
---
Herb Sutter (mailto:hsu...@peerdirect.com)
CTO, PeerDirect Inc. (http://www.peerdirect.com)
Contributing Editor, C/C++ Users Journal (http://www.cuj.com)
[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]
[...]
> Why errorcodes suck.
[...]
> 2) You can only return a small amount of information, usually a
> number.
How does "throw ErrorState" return more information than "return
ErrorState"?
> This is often insufficient to correct the error. For example, your
> fileopen function fails and returns an error 5, Access
> denied. Great, no problema. Wouldn't it be nice to know which
> filename failed? You say, "That's stupid! The calling function knows
> which filename it used!". Are you sure? Maybe that's why the
> fileopen failed, you weren't using the right filename to begin
> with. In fact I'd be willing to be that 99% of failed opens are
> caused by wrong filename.
The question of what to report is orthogonal to the question of how to
report it. The difference between return codes and exceptions only
addresses how errors are reported, not what information the report
contains.
--
James Kanze mailto:ka...@gabi-soft.de
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
Ziegelhüttenweg 17a, 60598 Frankfurt, Germany Tel. +49(069)63198627
> "Wil Evers" <bou...@dev.null> wrote in message
> news:jhi519...@tinus.intra.doosys.com...
> > Rather then letting the program muddle on, I believe it is usually
> > better to have it log as much error information as possible and
> > then abort, leaving it up to whatever/whoever invoked it to
> > take appropriate action.
>
> Repeat after me: It all depends on the program.
It all depends on the program :-).
> Every program will have different costs and benefits of "muddling
> on". If the cost is low enough (the program can't do much
> harm--it's not guiding missiles or anything) and/or the benefit is
> high enough (by not aborting, you at least give the user the chance
> to save her work), then muddling on is appropriate.
OK, I'll bite.
What we have is a program that just decided it can no longer trust
itself. We also have a user who just spent hours typing that crucial
document for that important business meeting tomorrow. Now what
should the program do?
Obviously, the bug should be fixed, but that is no help to our poor
user. At the very least, the program should try to report what went
wrong. And yes, it could try to save the user's work, provided the
saved copy is clearly marked as untrusted.
But should it ever try to return to its main loop, knowing that its
internal state is inconsistent, risking the chance of making things
worse for the user? Unless there is really nothing to fall back on
(like a user shell, a desktop OS, or a watchdog timer), my answer is
no. An unambiguous refusal to continue will at least stop the
marketing people from claiming there is no problem.
As a library writer, this is an important issue to me. By saying
that it all depends on the program, you're suggesting that throwing
an exception may be appropriate for reporting a programming error. I
only throw exceptions for unexpected conditions like running out of
resources. When I detect a programming error, my strategy is to call
some user-supplied routine, after which I force a core dump.
- Wil
--
Wil Evers, DOOSYS IT Consultants, Maarssen, Holland
[Wil underscore Evers at doosys dot com]
[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]
[...]
> 1) Set a global variable and trust that it will be checked. I recently
> asked a dozen attendees at on an Advanced C++ Development techniques
> course to raise their hands if they had ever checked errno. I was
> surprised that two actually claimed to have done so.
Surprised that the number was so high, or that it was so low. I've
never actually had a need to check errno. Errno doesn't tell you
whether an error has occured or not; it only defines what the error
was IF one occured. So the only time you would check errno is if you
wanted additional information concerning the type of error.
--
James Kanze mailto:ka...@gabi-soft.de
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
Ziegelhüttenweg 17a, 60598 Frankfurt, Germany Tel. +49(069)63198627
Exception-safety is another thing to think about, another issue to build into
your design. It does make it harder to produce a good design, yes, but the
difference is not great once you become accustomed to thinking about
exceptions.
Whether or not you throw exceptions from your own code you have to be aware
that exceptions are the standard way that much of the C++ runtime library
reports failure. You have to make your code exception-safe or be sure that
you don't use those parts of the library (or anything else that can throw).
I think, really, you *have* to write exception-safe code whether you want to
use exceptions yourself or not, so this shouldn't really affect your
decision.
> 2. Excpetions introduce a second path of control flow "behind the scenes",
> which increases the complexity of the code;
If a function can throw it will have multiple exit paths. I've always
followed a coding standard that prohibits multiple returns from a function
and exceptions essentially violate that standard. I do find that this makes
the code a little harder to follow, but it is no worse than allowing multiple
returns.
> 3. In order to do decent error-handling in constructors, you must use
> exceptions.
Well, it's true that a constructor can't return an error code, and that
throwing an exception is quite a nice way to report constructor failure. It's
not the only way, as other posters have pointed out, but I think it results
in much cleaner code than using tricks like an error flag in an object that
is set if the constructor fails.
> So, my questions are:
> a) should I use exceptions only for constructors and error codes for
> all other methods?
No, I'd say that if you are going to use exceptions at all you should use
them everywhere. Once you bite the bullet and make your code exception safe
and include code to catch some errors as exceptions there's very little
reason to avoid the technique in other cases.
> b) if exceptions are used in general, should functions return *only*
> error codes *or* throw exceptions? (i.e., is it ok to mix both in one
> method?)
It may be appropriate for some functions to return an error code for errors
that can be handled by their immediate caller but to throw an exception to
report errors that are too severe to correct and retry, but I would advise
you to use this technique sparingly and document it well because I have found
that that *can* make code confusing and hard to follow. (...or is it just
that I'm not yet used to reading code that does that?)
> c) should exceptions be used only for "exceptional" cases, or could they
> also be used for not-so-exceptional things, like bogus parameters passed
> in from the caller?
I don't think any two authorities will agree completely on what makes a case
"exceptional". I'd say that exceptions should only be used for runtime errors
- if by "bogus parameters" you mean something that is a coding error you
should probably detect them some other way, maybe an assertion. I see nothing
wrong with using an exception to report a bad parameter that is caused by bad
user input, badly formatted data, whatever.
> All insights and pointers will be greatly appreciated.
I've recently had occasion to rewrite some parts of a small application using
exceptions where I had previously used error codes. The application in
question uses two 3rd-party libraries which both use exceptions to report
errors. In my first version I had to wrap each call that could throw in a
try/catch block and convert any exception into an error code. I decided that
that was silly and - when I was asked to make some enhancements that were
going to add greatly to the number of calls that would have to be wrapped -
converted the whole application to use exceptions throughout.
The result was a much cleaner-looking (i.e. easier to read and to maintain)
body of code, I was able to remove almost all the try/catch blocks and all
the error-code handling code. This has been a great advantage.
There have been some sticking points, though:
- Neither of the 3rd-party libraries uses exceptions based on the standard
exception type so when I have to catch an exception I have to remember to
catch all the types of exception that can be thrown - I can't just catch by a
single base class. Of course, exception safety is about a lot more than
try/catch blocks - I recommend the section on exception safety in Herb
Sutter's "Exceptional C++" which explains the issues at least as well as
anything else I've seen.
- The two libraries contain conflicting definitions of a number of macros,
and their header files cannot both be included in the same source file (one
does not use namespaces and the other places 'using' directives in many of
its headers) so I've had to wrap one of the libraries in a "pImpl" class that
catches any exception thrown by the library and re-throws an exception type
defined by my application.
- both of the libraries throw exception objects that contain a text string
describing the condition that cause the exception to be thrown. These strings
are in English, but my application has to support more than one language.
I think that the moral of the story here is that exceptions thrown from
third-party libraries can be a problem if those libraries implement their own
exception objects not derived from the standard exception classes. If
libraries used a standard class such as domain_error (or a class derived
from, e.g. domain_error) it would be much easier for an application to manage
exceptions in a uniform manner - but the fact that domain_error uses a text
string to provide information about the error causes difficulties with
internationalization. My application's own exception objects hold message
numbers that are used to look up messages in a locale-dependent table for
display - it's a pity std::domain_error doesn't work this way.
One difficulty that has arisen from the use of exceptions as a general
error-reporting mechanism in the application is that exceptions may be thrown
from very low-level routines and caught at the top-level of the user
interface. When an exception is caught the handler knows nothing of the
context within which the exception was thrown. Everything has been unwound
neatly from the point of failure and the application is stable, but the
information available for display to the user often contains too little
contextual information to allow the user to work out what actually went
wrong. I'm trying to invent a mechanism for adding context information to
what is held in the exception object, so that a more meaningful message can
be displayed to the user - without catching the exception an rethrowing it at
every level! I'd be interested to hear whether anyone else has tackled this
problem before.
Cheers,
Daniel
[nospam.demon.co.uk is a spam-magnet. Replace nospam with sonadata to reply]
It's probably worth interjecting here - for those who don't know - that EPOC
is the OS supplied by Symbian for use in handheld computers, smartphones and
things of that ilk. EPOC code is written using an early version of the GNU
toolchain for the ARM processor that didn't have support for exceptions and
so the whole API is written to use an error-handling mechanism based around
functions that can "Leave" - a condition that must be handled using a
"Trap".
The Leave/Trap mechanisms is now so deeply enmeshed with the EPOC API that
it seems doubtful that it will ever be replaced with standard exceptions,
even though newer versions of the GNU tools are now available.
All of this is a kludge to facilitate structured handling of errors within
EPOC using a C++ subset that doesn't support exceptions - it is a good
kludge, in that it works well given the constraints of the environment - but
it is not strictly germane to the discussion of error handling in an
ISO-compliant C++ system.
Harri's observations:
> Note that using this idiom means that any class with initialisation stuff
> that might go wrong cannot be instantiated on the stack. This breaks most
> RIIA stuff you might want to do. It makes your code slower. It means you
> have to type in all that stuff repeatedly. It may also give you boils.
are certainly valid - I'd much rather use real C++ exceptions than the
Leave/Trap mechanism, though the latter has never yet given me boils!
Cheers,
Daniel
[nospam.demon.co.uk is a spam-magnet. Replace nospam with sonadata to reply]
Is it really that simple?
> void* operator new( size_t bytes )
> {
> static void* reserve = malloc( 40000 );
> void* p = malloc( bytes);
> if ( !p )
> {
> MessageBox( NULL, "You are running out of memory",
> "WARNING", NULL );
> free(reserve);
> p = malloc(bytes);
>
> }
> return p;
> }
>
> void operator delete( void* ptr )
> {
> free( ptr );
> }
Sadly, this will fail with:
struct Big
{
char buffer[50000];
};
void f ()
{
Big* p = new Big;
//...
}
The point, of course, is: how much reserve memory is enough? Just as
that spare gallon or 4 litres of fuel may be useless if you happen to
tap it in central Nevada or north Sweden, an arbitrary amount of extra
memory cannot guarantee that allocation will always succeed. Apart from
that:
- What is the appropriate thing to do for a user, and how is a user to
know?
- There are millions of systems that run without user interaction and
don't even have a screen to pop a message box on.
For these reasons, the argument is certainly not irrelevant, I think.
Gerhard Menzl
Because I need to stick __FILE__ and __LINE__ in there. Also, a companion
macro doesn't throw, it returns from the current function.
What you don't seem to be realizing is that exceptions are objects that
can contain virtually all the information you want them to contain.
Not only that but they can be handled all in one place where you can
have fairly lengthy or sophisticated error checking that would be very
awkward to place everywhere there is a function call on up the chain.
--
Regards,
Jeff
Sent via Deja.com
http://www.deja.com/
I think you answered your own question...
> Obviously, the bug should be fixed, but that is no help to our poor
> user. At the very least, the program should try to report what went
> wrong. And yes, it could try to save the user's work, provided the
> saved copy is clearly marked as untrusted.
> But should it ever try to return to its main loop, knowing that its
> internal state is inconsistent
It depends. :) I don't think one can make a single general rule for this
stuff.
> By saying
> that it all depends on the program, you're suggesting that throwing
> an exception may be appropriate for reporting a programming error.
Absolutely. For one thing, it's not always clear whether an error is a
"programming error" or not, which is why I tend not to distinguish
between them.
For example, in the app I'm working on, a customer wants to download a
file. The
database says the file's website's customer is unknown. Is that a programming
error, or a config error or a database load error or what? Is it
"exceptional"?
The answer is, I don't care. :) I'll let the user download the file. The
system
returns to its main loop and carries on.
> I only throw exceptions for unexpected conditions like running out of
> resources. When I detect a programming error, my strategy is to call
> some user-supplied routine, after which I force a core dump.
It seems to me that you're dictating how programming errors are handled
in your
library, and that's fine, of course. I prefer to let the client decide how to
handle errors (of all kinds), and that's what exceptions are for.
[Incidentally, some people seem to have interpreted this as a direct quote
of Dave, and it's not. I was just indenting it for emphasis, so that it
would stand out of the long paragraphs surrounding it and not be missed on
casual reading, because it was the key point.]
>> the main semantic differences being that exceptions:
>> a) can't be ignored;
>> b) don't have to be manually propagated up to a suitable handler;
>> c) require some more care in intermediate code so that stack
>> unwinding is safe.
>
>You missed out
> d) are more expensive when the exception is "often" thrown.
True.
>I'm not sure what you mean by error handling policy. Can you define
>it without reference to the two orthogonal considerations you've just
>mentioned?
Off the top of my head, in brief, to me an error handling policy for a
system should include identifying:
- what are the errors (what conditions are considered errors, and what
conditions aren't; categories of errors);
- what code should detect each category of error (usually easy, the closest
code detects it);
- how each category of error should be reported; and
- what code should handle each category of error (less easy to state as a
policy, and this can be affected by things like module/library boundaries),
and how (do we quit? do we make herculean efforts to recover and resume? do
we continue with degraded behavior?)
Or, more succinctly: "what's an error? who finds it? how does he report it?
who solves it, and how?" To a large degree the reporting method is
orthogonal to the other choices.
>I agree that return codes and exceptions are just mechanisms, and I
>can think of three reasons to choose one or other.
>
> 1) Performance: The "error" is sufficiently common that exceptions
> are too expensive, or sufficiently uncommon that checking return
> codes is too expensive. Of course, our estimate of how often
> it will fail depends on our assumptions about use. The classic
> example is opening files. Failing to open our own executable image
> is surely unexpected, but failure to open a file when our user
> had to type in a long path name by hand is surely the expected case.
Nit: Your point is good, but your example of responding to user input isn't.
A single keystroke of user input swamps EH time, so an exception in response
to user input isn't a performance issue.
> 2) Verbosity: "try {stuff();} catch (xyz) {fix();}" is more typing
> than "if (!stuff()) fix()" for certain values of stuff and fix.
> If the "error" is unlikely to be handled or even inspected by its
> immediate caller, then your point b favours the use of exceptions.
Not only that: By moving the error handling code away from "stuff()" it's
much easier to read the mainline of what's going on.
> It doesn't
> provide a killer argument in favour of exceptions in every case.
Code clarity can be a pretty convincing argument, at least to me. Of course
it assumes that the developer is equally proficient at writing correct code
using error codes and exceptions, and I admit that's not yet widely true.
Herb
---
Herb Sutter (mailto:hsu...@peerdirect.com)
CTO, PeerDirect Inc. (http://www.peerdirect.com)
Contributing Editor, C/C++ Users Journal (http://www.cuj.com)
[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]
I could give a joking reply of <insert large software company of choice
here>, or a mostly serious reply of the SETI analyzer. :-) So far the
"DetectSignal( Buffer& noise )" function hasn't returned a true positive.
>> The first two are clear advantages; the
>> last is now (finally) well-understood
>
>By you, Dave, and perhaps a few readers of this newsgroup. From what
>I've seen, I'd guess that this is only true for about 1% or 2% of the
>programmers, however.
Touche. But the number is increasing.
>IMHO, there are three aspects to error
>handling in general: detection, reporting and handling. Exceptions
>are irrelevant for the first and the last, and in many ways, just an
>implementation detail with regards to the second: they concern the
>how, but not the what.
Yup. (I'd add one more major aspect, namely error identification and
classification: for this project, what are the categories of errors, and
what things shall not be considered errors.)
>The other point I've noticed, and this still seems to be true, despite
>Dave's constant lecturing to the contrary, is that most people tend to
>think of exception safety, when they think of it at all, in terms of
>memory leaks, or at the most, resource management, and not in terms of
>total program coherence. If resource management were the only
>concern, exception safety would be trivial.
Actually, I think it's exactly the opposite: If you know enough to write
exception-safe code for those reasons, you pretty much know what you need to
know to write exception-safe code in general. The difficulty with exception
handling isn't so much identifying who should throw, or who should catch
(and how to catch), but getting the code in the middle to stay out of the
way when a stack-unwinding operation (a.k.a. "lightning bolt") could come
through it at any point where there's a function call.
Herb
---
Herb Sutter (mailto:hsu...@peerdirect.com)
CTO, PeerDirect Inc. (http://www.peerdirect.com)
Contributing Editor, C/C++ Users Journal (http://www.cuj.com)
[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]
Steven Rumbalski
Sent via Deja.com
http://www.deja.com/
[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]
I have never seen a private or public API set that does that however.
I think if you did that, you'd be combining the worse parts of
exceptions with the worse parts of return-value-used-as-error-flag.
You'd be constructing, copying and destructing entire objects even
when they weren't necessary (non-error returns) which exceptions don't
do. You'd have to check the returned structure for success or failure
just like a number return code before using it in an expression
causing "extended-function-call-return-check-semantics"
Walt Howard
Francis Glassborow <francis.g...@ntlworld.com> writes:
> In article <wkn1dzm...@wallyware.com>, Walt Howard
> <wa...@wallyware.com> writes
> >You left out a big one: Exceptions can return any type of object, and all the
> >error-information you need.
>
> So can return values.
[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]
"Gabriel Zachmann" <za...@igd.fhg.de> wrote in message
news:slrn93a6ke...@schwind.igd.fhg.de...
> c) should exceptions be used only for "exceptional" cases, or could they
> also be used for not-so-exceptional things, like bogus parameters
passed
> in from the caller?
In my work, I develop server middleware code - it's really important that we
don't core dump. As a general rule, my approach to exceptions is this: "In
a normally functioning program with valid input and environment no
exceptions are ever thrown" (as with every rule, there are exceptions...).
So, any condition which is "normal", no matter how uncommon, is dealt with
in the normal flow of the code (and generally indicated by function return
values, etc). Exceptions are reserved for "something really bad happened".
I wrap the guts of the server processes with (essentially) a catch (...)(see
below), and make sure everything inside is exception safe (i.e. no resources
are leaked if exceptions are thrown). For this type of application, this
generally permits restoring the system to a consistent state after an
exception and the server can go on processing other requests. For other
application domains, a different strategy may be better.
(I say essentially catch(...) because in my application, the main program is
Java (ugh). We catch all C++ (and on Windows, all SEH) exceptions, wrap
them up in a Java exception object & ship them up to Java where the real
top-level handler resides).
-cd
It surprises me that it was so high. WRT errno, in the C89 math libraries,
for many of the functions the ONLY prtable way to test for errors was to
check errno after a call to tan(), for example. Not all platforms support
such things as +/-INF and NANs. And yet I have taught C++ to several
seasoned C scientific programmers who didn't even know about errno.
Mike Terrazas
That exceptions are a very inefficient way of dealing with local errors.
Error returns are much more efficient and where _expect_ the calling
function to be able to deal with it, it would seem reasonable.
Uniformity of style means that in similar situations you do similar
things. But there are many forms of 'error' and we should consider what
is appropriate for each. For example, an input function to get an
integer within a specific range from the keyboard will often fail, but
it is just about certain that the calling function knows how to handle
failure and should be encouraged to do so by using an error return code.
Typically in this case I would pass a write-back variable as a parameter
and return a bool to indicate success/failure.
Francis Glassborow Association of C & C++ Users
64 Southfield Rd
Oxford OX4 1PA +44(0)1865 246490
All opinions are mine and do not represent those of any organisation
[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]
>Matthew Collett <m.co...@auckland.ac.nz> writes:
>
>>In principle: an exception occurs when a function cannot satisfy its
>>stated or implied post-conditions even though the caller met its
>>pre-conditions.
>
>OK, I'll bite: Does that include warnings and success-with-info?
If the warning or info are really just that, they presumably can be
ignored without compromising the safety of the code (if not necessarily
without compromising its functionality). So passing the information
back as some type of return code (which the caller may then choose to
ignore) seems to me more appropriate than using an exception (which he
may not).
>Also, how
>should other problems (such as parameter and precondition errors) be
>reported?
>
>Herb
I thought someone might ask this one. My take on this is that
precondition errors are strictly speaking not exceptions but bugs, and
should 'never' happen in correct code. If such an 'impossible' event
_does_ occur, throwing an sternly-worded exception (that is caught at
the highest level in the code and results in the reporting or logging of
the bug) is obviously a reasonable response. One way of viewing this is
that the _calling_ function was probably already unable to complete
successfully, and hence should have thrown, but hadn't realised it.
Best wishes,
Matthew Collett
--
The word "reality" is generally used with the intention of evoking sentiment.
-- Arthur Eddington
[...]
> >IMHO, there are three aspects to error handling in general:
> >detection, reporting and handling. Exceptions are irrelevant for
> >the first and the last, and in many ways, just an implementation
> >detail with regards to the second: they concern the how, but not
> >the what.
> Yup. (I'd add one more major aspect, namely error identification and
> classification: for this project, what are the categories of errors,
> and what things shall not be considered errors.)
That's the "what" in reporting, above. I suppose you could consider
it separately, but I find that it tends to be bound to the how, at
least to some degree.
> >The other point I've noticed, and this still seems to be true,
> >despite Dave's constant lecturing to the contrary, is that most
> >people tend to think of exception safety, when they think of it at
> >all, in terms of memory leaks, or at the most, resource management,
> >and not in terms of total program coherence. If resource
> >management were the only concern, exception safety would be
> >trivial.
> Actually, I think it's exactly the opposite: If you know enough to
> write exception-safe code for those reasons, you pretty much know
> what you need to know to write exception-safe code in general.
I'm not sure. I see two problems. The first is that while it is
generally immediately obvious what to do with regards to resources, it
is not always so obvious with regards to other things. I've rarely
heard the Memento pattern mentioned in conjunction with exceptions,
for example, although it would seem to be fundamental. The second is
that it is generally immediately apparent that you have a resource,
and must free it. Consistency problems are less apparent.
But of course, this is just as true for return codes or other error
reporting mechanisms. Perhaps what you meant to say is that once
you've learned the basic exception-safe idiom, applying it to the
problems you see is not difficult. And whether you see the problem or
not is pretty much independant of the error reporting mechanism;
regardless of the mechanism, you have to cleanly back out of the
processing in process.
--
James Kanze mailto:ka...@gabi-soft.de
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
Ziegelhüttenweg 17a, 60598 Frankfurt, Germany Tel. +49(069)63198627
> What you don't seem to be realizing is that exceptions are objects
> that can contain virtually all the information you want them to
> contain.
What you don't seem to be aware of is that exceptions are whatever you
want them to be: objects or primitives, and that the same holds for
return codes.
Gerhard Menzl
> Sure, all your functions could return a structure or object to be
> used to determine error state.
> I have never seen a private or public API set that does that
> however.
Funny. It's the most frequent solution I've seen.
> I think if you did that, you'd be combining the worse parts of
> exceptions with the worse parts of return-value-used-as-error-flag.
> You'd be constructing, copying and destructing entire objects even
> when they weren't necessary (non-error returns) which exceptions
> don't do. You'd have to check the returned structure for success or
> failure just like a number return code before using it in an
> expression causing "extended-function-call-return-check-semantics"
You have to check the error code. That's the whole point of it. As
for the extra construction/copying, obviously, you design the thing so
that construction/copy is cheap when no error information is present.
--
James Kanze mailto:ka...@gabi-soft.de
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
Ziegelhüttenweg 17a, 60598 Frankfurt, Germany Tel. +49(069)63198627
> > The question of what to report is orthogonal to the question of
> > how to report it. The difference between return codes and
> > exceptions only addresses how errors are reported, not what
> > information the report contains.
> What you don't seem to be realizing is that exceptions are objects
> that can contain virtually all the information you want them to
> contain.
I know that. What you don't seem to be realizing is that return codes
are objects that can contain virtually all of the information you want
them to contain.
> Not only that but they can be handled all in one place where you can
> have fairly lengthy or sophisticated error checking that would be
> very awkward to place everywhere there is a function call on up the
> chain.
First, of course, is it always appropriate for *all* of the error
handling to be in one place? Typically, there are different degrees
of errors, which are handled at different levels. Basically, the
difference between exceptions and return codes is that with
exceptions, you're favorizing propagating the error up, and with
return codes, you're favorizing handling it immediately. With
exceptions, you're providing implicit and invisible propagation. With
return codes, you're requiring the programmer to think about it, and
explicitly propagate (or handle, as the case may be).
Secondly, it is arguable whether hiding something as vital as error
handling is a good choice. In most of the applications I've been
involved with, we've found it preferrable to consider error handling
as part of the basic application, and design it into all of the
algorithms. In this sense, errors are "normal", and not exceptional.
Of course, most of these designs date from a time when we didn't have
a choice, but I must say, they worked, and they gave remarkably robust
code.
At the other extreme, I now work almost exclusively in Java. And
there is nothing more frustrating than Java's insistance on throwing
exceptions when you want to handle the error immediately. While I can
understand things like out of memory being handled by exceptions --
Java's not designed for robust applications anyway, so arguments
concerning program proof or programmer understanding of exception
safety are largely moot -- I've yet to encounter a case where I didn't
want to handle "file not found" immediately, and the use of exceptions
complicated the code.
--
James Kanze mailto:ka...@gabi-soft.de
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
Ziegelhüttenweg 17a, 60598 Frankfurt, Germany Tel. +49(069)63198627
My point was only really that it is possible to encapsulate two phase
construction, where the real constructor cannot throw, into a factory
function in order to prevent use of an uninitialised object. I was just
mentioning the reasoning behind this in EPOC in case people were interested.
Anyway, the entire EPOC TRAP/Leave mechanism might not be useful in a
standard-conforming environment, but plenty of useful lessons can be learnt
from it and applied to more conventional programming.
Mark Wilden wrote:
>
> > What about a constructor like
> >
> > struct X{
> > X() { try { Init(); /* ... */ } catch(...){} }
> > void Init() { /* ... */}
> > };
>
> Well, I guess that's another approach to this issue: Have Init() throw an
> exception, which the constructor then ignores. :)
>
> Sorry, I don't see how this would be a solution.
Sorry, a solution for what? I really forgot you question, I thought
you were looking a non-throwing constructor?
I thought the above code was quite self-explaining, but I should have
been more explicitly - of course the constructor does not have to
ignore the exceptions, you might handle these as you like, simply add
the code inside the parentheses:
X() { try { Init(); /* ... */ } catch(...){/* HERE! */} }
Ali
--
Albrecht Fritzsche, Software Developer
alfabet meta-modelling ag,
leibnitzstr. 53, 10629 berlin, germany
http://www.alfabet.de
> "Wil Evers" <bou...@dev.null> wrote in message
> news:24pc19...@tinus.intra.doosys.com...
> >
> > What we have is a program that just decided it can no longer trust
> > itself. We also have a user who just spent hours typing that crucial
> > document for that important business meeting tomorrow. Now what
> > should the program do?
>
> I think you answered your own question...
>
> > Obviously, the bug should be fixed, but that is no help to our poor
> > user. At the very least, the program should try to report what went
> > wrong. And yes, it could try to save the user's work, provided the
> > saved copy is clearly marked as untrusted.
>
> > But should it ever try to return to its main loop, knowing that its
> > internal state is inconsistent
>
> It depends. :) I don't think one can make a single general rule for this
> stuff.
>
> > By saying
> > that it all depends on the program, you're suggesting that throwing
> > an exception may be appropriate for reporting a programming error.
>
> Absolutely. For one thing, it's not always clear whether an error is a
> "programming error" or not, which is why I tend not to distinguish
> between them.
I think it's pretty clear. Each functions has pre-conditions that should be
written down in some place
that 's convenient for the programmers writing calls to the function.
When those pre-conditions are violated, then a programming error has occurred.
>
> For example, in the app I'm working on, a customer wants to download a
> file. The
> database says the file's website's customer is unknown. Is that a programming
> error, or a config error or a database load error or what?
That depends on the preconditions specified by the downloading function. In
this case, my guess is that
the caller was not expected to check database consistency before downloading.
In that case, the inconsistency
is not a programming error, at least not in the current process.
> In article <91e6fp$nn0$1...@nnrp1.deja.com>, srumb...@my-deja.com writes
> >I'm a C++ newbie, so I wonder if you could explain something for me.
> >Why use 3 at all? You seem (and maybe I misunderstand) to be saying
> >that error codes should be used when the calling function may be able
> >to fix the problem, while exceptions should be used when the problem
> >needs to be handled by a function further back on the call stack.
> >However, exceptions seem to be suited for the situations mentioned in 3
> >as well as in 4. If this is so, wouldn't it be better to use just
> >exceptions to maintain uniformity of style? Also, you mention in 3
> >that it is possible to ignore an error return. Isn't it also possible
> >to ignore an exception. (By ignore I mean catch it and then ignore
> >it.) What am I missing?
>
> That exceptions are a very inefficient way of dealing with local errors.
> Error returns are much more efficient and where _expect_ the calling
> function to be able to deal with it, it would seem reasonable.
> Uniformity of style means that in similar situations you do similar
> things. But there are many forms of 'error' and we should consider what
> is appropriate for each. For example, an input function to get an
> integer within a specific range from the keyboard will often fail, but
> it is just about certain that the calling function knows how to handle
> failure and should be encouraged to do so by using an error return code.
> Typically in this case I would pass a write-back variable as a parameter
> and return a bool to indicate success/failure.
I think this is a poor example. A function that reads a string and then
either converts it to an integer or returns an error is almost useless,
precisely because every caller will have to wrap the call with
error-handling code. A useful function would take care of re-prompting
until the string can be converted, or until it becomes impossible to obtain
further input due to EOF.
Throwing an exception on EOF seems perfectly reasonable.
> If a function can throw it will have multiple exit paths. I've always
> followed a coding standard that prohibits multiple returns from a function
> and exceptions essentially violate that standard. I do find that this makes
> the code a little harder to follow, but it is no worse than allowing multiple
> returns.
>
I've seen this 'coding standard' a few times in my career, but I always assumed
it was left over from the
early days of structured programming, and was intended to prevent use of
alternate returns in FORTRAN or assembly language programming. In those
languages it is possible for a function to return control to a location
different from the calling location.
I don't remember the exact syntax, but it was something like this in FORTRAN:
F=ARCTAN(X,Y,&10)
C Normal return here
...
C Error return here
10 ...
REAL ARCTAN(X,Y,I)
C If both arguments zero, then return to error handler
IF (X .EQ. 0 .AND. Y .EQ. 0) RETURN &I
C Normal return
ARCTAN=ATAN(X,Y)
RETURN
This feature was justifiably deprecated along with arithmetic-if
and other arcane FORTRAN control structures.
This is simply not an issue in modern structured languages.
Yes, I realized that after I posted.
--
Regards,
Jeff
Sent via Deja.com
http://www.deja.com/
[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]
> "James Kanze" <James...@dresdner-bank.com> wrote in message
> news:3A39DDE9...@dresdner-bank.com...
> > Francis Glassborow wrote:
> > [...]
> > > 1) Set a global variable and trust that it will be checked. I recently
> > > asked a dozen attendees at on an Advanced C++ Development techniques
> > > course to raise their hands if they had ever checked errno. I was
> > > surprised that two actually claimed to have done so.
> > Surprised that the number was so high, or that it was so low.
> > I've never actually had a need to check errno. Errno doesn't tell
> > you whether an error has occured or not; it only defines what the
> > error was IF one occured. So the only time you would check errno
> > is if you wanted additional information concerning the type of
> > error.
> It surprises me that it was so high. WRT errno, in the C89 math
> libraries, for many of the functions the ONLY prtable way to test
> for errors was to check errno after a call to tan(), for example.
> Not all platforms support such things as +/-INF and NANs. And yet I
> have taught C++ to several seasoned C scientific programmers who
> didn't even know about errno.
Maybe because it doesn't work. The only copy of the C standard I have
handy is C99, and the math parts are one area where things have
changed, but from memory, the defacto standard way of signaling an
error was to call matherr. As far as the standard went, I think that
such things were undefined behavior.
And don't forget that the standard *only* defined errno in case where
the function had already reported an error. Function were allowed to
do anything they wanted with errno when no error had occured. I've
actually seen this -- a successful printf which set errno. I can't
quite imagine it happening in one of the mathematical routines, but
you'd still have to systematically set errno to 0 before each call, in
order to not get a preceding error.
--
James Kanze mailto:ka...@gabi-soft.de
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
Ziegelhüttenweg 17a, 60598 Frankfurt, Germany Tel. +49(069)63198627
>At the other extreme, I now work almost exclusively in Java. And
>there is nothing more frustrating than Java's insistance on throwing
>exceptions when you want to handle the error immediately. While I can
>understand things like out of memory being handled by exceptions --
>Java's not designed for robust applications anyway, so arguments
>concerning program proof or programmer understanding of exception
>safety are largely moot -- I've yet to encounter a case where I didn't
>want to handle "file not found" immediately, and the use of exceptions
>complicated the code.
That seems somewhat strange to me. I thought Java handled this in a
fairly clean manner. If you expect the file to exist before you try
to open it, you can use File.exists() to check before hand. Then, if the file
is not there when you try to open it, is it not a truly exceptional case?
( Obviously we can all draw up scenarios where this can occur, but my point
is that it would be unusual and not expected, and hence what seems to be a
great candidate for an exception error-handling strategy ).
God bless,
-Toby Reyelts
--
Toby Reyelts
331107 Georgia Tech Station Atlanta Georgia 30332-1365
Internet: gt1...@prism.gatech.edu
Exceptions are more appropriate for error conditions that should
NOT be ignored, and which can not be handled at the point they
occur. There are a lot of circumstances where I/O errors
can be safely ignored or the information is at hand immediately to
recover from the error (eg we tried to open a file this way,
so failure is probably caused by that). Throwing an exception
forces the programmer to explicitly handle errors that could
otherwise have been safely ignored, or simply adds overhead
in a situation where recovery is immediately possible.
I forget, now, all the original reasons for adopting that 'standard' - though
source-code readability was certainly the main factor.
Another issue was debuggability, if there's only one return it's easy to put a
breakpoint on it, if there are several its easy to overlook one and find that the
function you were debugging has returned through a path you'd forgotten about -
and all of its local variables have gone out of scope so you can't tell why. This
issue is now largely academic because most good debuggers will now accept a
breakpoint on the closing brace of a function so that it will be triggered by any
return from within the function.
We have the same problem with exceptions, though. If a function can throw from
numerous places it's hard to breakpoint them all.
Cheers,
Daniel
[nospam.demon.co.uk is a spam-magnet. Replace nospam with sonadata to reply]
> James Kanze <James...@dresdner-bank.com> wrote:
> >At the other extreme, I now work almost exclusively in Java. And
> >there is nothing more frustrating than Java's insistance on
> >throwing exceptions when you want to handle the error immediately.
> >While I can understand things like out of memory being handled by
> >exceptions -- Java's not designed for robust applications anyway,
> >so arguments concerning program proof or programmer understanding
> >of exception safety are largely moot -- I've yet to encounter a
> >case where I didn't want to handle "file not found" immediately,
> >and the use of exceptions complicated the code.
> That seems somewhat strange to me. I thought Java handled
> this in a fairly clean manner. If you expect the file to exist
> before you try to open it, you can use File.exists() to check before
> hand. Then, if the file is not there when you try to open it, is it
> not a truly exceptional case? (Obviously we can all draw up
> scenarios where this can occur, but my point is that it would be
> unusual and not expected, and hence what seems to be a great
> candidate for an exception error-handling strategy ).
The problem is that normally, you want to handle the problem
immediately, before going any further. You don't want the error to
propagate up. There are certainly special cases, where the
impossibility of opening a file should result in aborting the current
operation, but they are generally rare. And when you actually want to
treat an error for a specific function immediately, a try/catch is
definitly more awkward and more verbose than a simple if.
--
James Kanze mailto:ka...@gabi-soft.de
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
Ziegelhüttenweg 17a, 60598 Frankfurt, Germany Tel. +49(069)63198627
> Francis Glassborow <francis.g...@ntlworld.com> wrote:
>
> > So can return values.
>
> Not really.
Yes, really.
> Error foo (); returns an 'Error' and nothing else.
And if I want to define Error to be an object that can contain
anything I want it to contain?
Ciao,
Peter K.
--
Peter J. Kootsookos Wb: www.clubi.ie/PeterK
"Here comes the future and you can't run from it,
If you've got a blacklist I want to be on it"
- 'Waiting for the great leap forwards', Billy Bragg
> Walt Howard wrote:
>
> > Sure, all your functions could return a structure or object to be
> > used to determine error state.
>
> > I have never seen a private or public API set that does that
> > however.
>
> Funny. It's the most frequent solution I've seen.
>
All the API's I've seen return a single integer or pointer where
anything non-zero can sometimes be an error, or 0 is sometimes an
error. The entire Windows API does this. COM does this, standard C
library does this (barely). What API set do you use that actually
returns a structure (multiple members) or an object (multiple members)
as a way to signal errors?
Walt Howard
Exceptions find their strength when the error can't be handled where it
occurred, that's true, but that doesn't prohibit the degenerate case. Also,
how's the designer of a library going to know when an error can be handled? He
can't, so he should use exceptions.
> Throwing an exception
> forces the programmer to explicitly handle errors that could
> otherwise have been safely ignored, or simply adds overhead
> in a situation where recovery is immediately possible.
You're no more forced to handle exceptions than you are to deal with return
codes. It's a little harder to ignore errors, but not impossible.
if (!foo()) // handle error
try { foo() } catch (/**/) { /* handle error */ }
It's more verbose, but I don't see how it's more awkward. On the other hand, I'm
not sure what "awkward" means in the context of computer programming.
> The problem is that normally, you want to handle the problem
> immediately, before going any further. You don't want the error to
> propagate up. There are certainly special cases, where the
> impossibility of opening a file should result in aborting the current
> operation, but they are generally rare. And when you actually want to
> treat an error for a specific function immediately, a try/catch is
> definitly more awkward and more verbose than a simple if.
>
IMHO, there is never one good interface. I just finished a project for
school which involved a simple client-proxy-server system. There was a lot
of shared code between them. Sometimes a decision on this code which made a
lot of sense for the client, would make no sense for the proxy or the
server. What is an error which will be handled in the next layer? Dependson
the next layer, doesn't it? So I mosty resorted to return codes + wrappers.
I also wrote a lot of wrappers around Unix calls.
I think this was a good solution.
Want an exception on error? call Function.
Want an error code? call function.
On the standard side there is operator new(size_t) and operator
new(size_t,std::nothrow_t) which ilustrates the same idea.
Regards,
--
Luis Coelho.
Check out my game of Hearts, a card game, for KDE at:
http://www.geocities.com/deepblack9/index.html
The designer of a library usually has some sense of likely use
cases. Otherwise, there would be no requirement for the library
in the first place. Errors that get reported to a caller will
fall into three (for sake of discussion) distinct categories.
1) Those that can be safely (or optionally) ignored.
2) Those that the caller can handle immediately.
3) Those that the caller can not handle immediately,
and must be passed further up the call chain.
The first case is most suitable for implementation by return
codes. The third is most suitable for implementation using
exceptions. The second is suitable for either scheme depending
on context: if the caller can safely ignore most errors, but
there are some that it may want to handle, it is appropriate
to report errors by return code. If the caller can only handle
a few errors, and must pass most up the call chain, then
exceptions are appropriate.
With I/O libraries, most likely errors fall into the first two
categories.
>
> > Throwing an exception
> > forces the programmer to explicitly handle errors that could
> > otherwise have been safely ignored, or simply adds overhead
> > in a situation where recovery is immediately possible.
>
> You're no more forced to handle exceptions than you are to deal with return
> codes. It's a little harder to ignore errors, but not impossible.
>
I must be missing something. It is not possible to ignore exceptions.
It is possible to deliberately swallow an exception (eg catch it, do
nothing, and don't rethrow), but that is not ignoring the exception.
It is a deliberate action to prevent the exception propagating.
With error codes, doing nothing is a default choice (i.e. unless
you choose to handle it, it is ignored).
> if (!foo()) // handle error
> try { foo() } catch (/**/) { /* handle error */ }
> It's more verbose, but I don't see how it's more awkward. On the
> other hand, I'm not sure what "awkward" means in the context of
> computer programming.
Well, you got the try block version wrong, but the if version
right:-). (You forgot the ';' after the function call.)
Seriously, it may just be a question of habit. I use exceptions
regularly in Java (don't have any choice). I don't find it awkward
when the try block encompasses a large number of statements, any of
which can throw; it almost feels natural then. But most of the time,
what I'm trying to do is something along the lines of:
ReturnCode rc = foo() ;
if ( ! rc ) {
// Log error, maybe attempt alternatives...
// Generate a degenerate return value.
}
// Process whatever, no further errors possible...
// Generate the normal return value.
}
return ... ;
Rewritten, it becomes:
try {
foo() ;
// Process whatever...
// Generate normal return value.
} catch ( ... ) {
// Log error, maybe attempt alternatives...
// Generate a degenerate return value.
}
return ... ;
The error is triggered by foo. The error handling concerns what
happened in foo. It seems much more appealling, to me at least, that
the error handling be physically adjacent to the call to foo.
--
James Kanze mailto:ka...@gabi-soft.de
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
Ziegelhüttenweg 17a, 60598 Frankfurt, Germany Tel. +49(069)63198627
A lot of C++ APIs are thin wrappers around C APIs - which tend to
return fundamental types.
The technique of combining a return status and a return value has been
known a long time - I'm sure its mentioned in Barton and Nackman
(1994?). It goes something like (cut and paste from an internal API I'm
working with):
template<typename rtype>
class status_return
{
public:
typedef rtype return_type;
/// Default construct a successful return
status_return();
/// Construct a successful return
status_return(return_type value);
/// Construct a mixed return (usually a warning)
status_return(status exit_status, return_type value);
/// Construct an unsuccessful return
status_return(status exit_status);
/// Converts to "true" if (and only if) status_success/warning.
operator bool() const;
///
const status& get_status() const;
///
const return_type& get_value() const;
// . . .
};
IIRC James has posted a varient that makes a fuss at runtime if the
status isn't accessed by the client code.
--
Alan Griffiths http://www.octopull.demon.co.uk/
Senior Systems Consultant, Experian tel: +44 115 968 5118
Chair, Association of C and C++ Users http://accu.org/
Sent via Deja.com
http://www.deja.com/
[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]
> Another issue was debuggability, if there's only one return it's easy to put a
> breakpoint on it, if there are several its easy to overlook one and find that the
> function you were debugging has returned through a path you'd forgotten about -
> and all of its local variables have gone out of scope so you can't tell why. This
> issue is now largely academic because most good debuggers will now accept a
> breakpoint on the closing brace of a function so that it will be triggered by any
> return from within the function.
>
> We have the same problem with exceptions, though. If a function can throw from
> numerous places it's hard to breakpoint them all.
>
Uh, no. It's much easier to set breakpoints with exceptions. Since an
exception is an object, it has a constructor and you can catch every
throw of that object with a breakpoint in its constructor.
Walt Howard
Maybe this depends on the application. In the kind I have worked on, the
file name would come from a user-interface and would typically be picked
from a list of existing files. For it not to exist would imply it
disappeared between the picking and the opening. This is certainly rare
enough to be considered an exception.
I don't see how the code can resolve the problem locally. It typically
means going back to the UI to ask for another name. The code that opens
the file can't very well do this itself as it should be decoupled from
the UI. Throwing an exception seems very natural here.
Whatever - the Java situation is made worse, in my view, by the fact that
the FileNotFoundException is a declared exception. This means it must
either be handled explicitly or propagated explicitly. Detailed "throws"
clauses tend to spread through the call tree, and have to be updated when
methods change. This is extra work for no real benefit. Worse, it gives a
false sense of security because people imagine they only have to deal
with the declared exceptions and forget about the undeclared ones. In
reality, almost any routine can throw an exception because almost any
routine may try a memory allocation.
In C++ exceptions are much less intrusive. Most C++ code needs only to
know that an exception is possible and doesn't care what it is. The only
useful exception specification is an empty one.
Dave Harris, Nottingham, UK | "Weave a circle round him thrice,
bran...@cix.co.uk | And close your eyes with holy dread,
| For he on honey dew hath fed
http://www.bhresearch.co.uk/ | And drunk the milk of Paradise."
If foo() is the only thing you're interested in, then you don't need to
physically separate the error handling. Instead of
try {
foo() ;
// Process whatever...
// Generate normal return value.
} catch ( ... ) {
// Log error, maybe attempt alternatives...
// Generate a degenerate return value.
}
return ... ;
I would do
int rc = success;
try
foo();
}catch (...) {
// Log error, etc.
rc = failure;
}
// Process whatever
return rc;
I'm having trouble coming up with an example of this. In COM, it's possible
for
a function to "succeed with information", but I certainly haven't seen much
need
to do that.
> 2) Those that the caller can handle immediately.
> 3) Those that the caller can not handle immediately,
> and must be passed further up the call chain.
>
> The first case is most suitable for implementation by return
> codes. The third is most suitable for implementation using
> exceptions. The second is suitable for either scheme depending
> on context:
Exactly. And the writer of a library can't know what that precise context is.
> > You're no more forced to handle exceptions than you are to deal with
return
> > codes. It's a little harder to ignore errors, but not impossible.
> >
>
> I must be missing something. It is not possible to ignore exceptions.
> It is possible to deliberately swallow an exception (eg catch it, do
> nothing, and don't rethrow), but that is not ignoring the exception.
> It is a deliberate action to prevent the exception propagating.
> With error codes, doing nothing is a default choice (i.e. unless
> you choose to handle it, it is ignored).
Semantics. By "ignore" I was talking about wrapping a function in a try/catch
that ignores the result.
> James Kanze <James...@dresdner-bank.com> writes:
> > Walt Howard wrote:
> > > Sure, all your functions could return a structure or object to
> > > be used to determine error state.
> > > I have never seen a private or public API set that does that
> > > however.
> > Funny. It's the most frequent solution I've seen.
> All the API's I've seen return a single integer or pointer where
> anything non-zero can sometimes be an error, or 0 is sometimes an
> error. The entire Windows API does this. COM does this, standard C
> library does this (barely). What API set do you use that actually
> returns a structure (multiple members) or an object (multiple
> members) as a way to signal errors?
The classical Unix solution was to return a singular value, with
additional error information in errno. But that was long before C++.
I've never used the Windows API, nor COM, so I wouldn't know about
them. But in general: if the library doesn't want to give you the
necessary information, what makes you think that using exceptions will
change their ideas?
I was mainly talking about the application software, though. Most of
the error codes I've seen from public API have been from the C level,
and were fairly old. For the last seven or eight years, *every*
application I've worked on has used a ReturnCode class for error
propagation. In one case, the additional error information was in a
global variable, like errno; otherwise, the Flyweight pattern was used
to add it to the ReturnCode, without making copying of the return code
excessively expensive.
--
James Kanze mailto:ka...@gabi-soft.de
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
Ziegelhüttenweg 17a, 60598 Frankfurt, Germany Tel. +49(069)63198627
> Exceptions find their strength when the error can't be handled where
> it occurred, that's true, but that doesn't prohibit the degenerate
> case. Also, how's the designer of a library going to know when an
> error can be handled? He can't, so he should use exceptions.
Typically, the designer of a library does have a pretty good idea what
the library is going to be used for, and whether errors can be
ignored, handled locally, or only on a global level. Even for
something as general as std::vector, it's a good bet that no
application will be able to ignore bad_alloc, and even that no
application will be able to handle it locally.
If, however, the library designer cannot know, the correct solution is
a return code. Why should people who cannot use the exception pay its
price (and I'm not talking only about performance, but the added
complexity of writing a try/catch block)? For those who need the
exception, of course, all it takes is a single if to get it.
--
James Kanze mailto:ka...@gabi-soft.de
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
Ziegelhüttenweg 17a, 60598 Frankfurt, Germany Tel. +49(069)63198627
> James Kanze wrote:
> > The problem is that normally, you want to handle the problem
> > immediately, before going any further. You don't want the error to
> > propagate up. There are certainly special cases, where the
> > impossibility of opening a file should result in aborting the current
> > operation, but they are generally rare. And when you actually want to
> > treat an error for a specific function immediately, a try/catch is
> > definitly more awkward and more verbose than a simple if.
> IMHO, there is never one good interface. I just finished a project
> for school which involved a simple client-proxy-server system. There
> was a lot of shared code between them. Sometimes a decision on this
> code which made a lot of sense for the client, would make no sense
> for the proxy or the server. What is an error which will be handled
> in the next layer? Dependson the next layer, doesn't it? So I mosty
> resorted to return codes + wrappers. I also wrote a lot of wrappers
> around Unix calls. I think this was a good solution.
> Want an exception on error? call Function.
> Want an error code? call function.
Hate the naming convention, but otherwise a good idea for a general
purpose library.
> On the standard side there is operator new(size_t) and operator
> new(size_t,std::nothrow_t) which ilustrates the same idea.
Another alternative that I've occasionally used: a user defined
callback. If it returns, return an error. But give it enough
information that the user can throw a significant error if he wants.
Typically, using a static member is a good solution for the callback.
All instances of the class get the same behavior, and the user doesn't
have to distinguish at each call.
--
James Kanze mailto:ka...@gabi-soft.de
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
Ziegelhüttenweg 17a, 60598 Frankfurt, Germany Tel. +49(069)63198627
Especially file opens. Failure to open a file borders on catastrophic.
Why?
Disk Full: Impending Disaster for entire system.
Access Error: Program running under wrong user privileges.
File in exclusive use by someone else.
User Error: Requires user intervention. File open/close AND user
interaction is more than one function should be doing.
Doesn't Exist: Whatever part of your program, it's got to be more than
one function, was depending on this file existing is
irrelevant now. Throw an exception to return that
entire section of code. Does your openfile function really
understand what to do in this case? If so, your functions
are way too big. People whose entire program is contained
in main() are not good candidates for exception usage. I'm
not implying anything by this, except that I have seen that
quite a bit.
Walt Howard
> James Kanze wrote:
>
> > The problem is that normally, you want to handle the problem
> > immediately, before going any further. You don't want the error to
> > propagate up. There are certainly special cases, where the
> > impossibility of opening a file should result in aborting the current
> > operation, but they are generally rare. And when you actually want to
> > treat an error for a specific function immediately, a try/catch is
> > definitly more awkward and more verbose than a simple if.
> >
>
> IMHO, there is never one good interface. I just finished a project for
> school which involved a simple client-proxy-server system. There was a lot
> of shared code between them. Sometimes a decision on this code which made a
> lot of sense for the client, would make no sense for the proxy or the
> server. What is an error which will be handled in the next layer? Dependson
> the next layer, doesn't it? So I mosty resorted to return codes + wrappers.
> I also wrote a lot of wrappers around Unix calls.
> I think this was a good solution.
You're describing the exact things that exceptions are good for! You
simply throw the error with no concern for how its going to be
caught. This sounds like purposeful ignorance but its the exact right
thing to do. You don't want to know how the caller is going to handle
it! If you did, you would alter the caller to fit the particular
situation which would make the code less reuseable.
The current function knows there has been an error, but it doesn't
know how to handle it. Throw the error and whoever comes later will
have to deal with it.
Exceptions loosen (decouple) the dependency between functions, with
this one small gotcha. There has got to be a good, exception base
class that is standard. Without that exceptions will be good, but less
than ideal.
Maybe this whole disagreement about exceptions is because people write
functions of varying sizes. People who write large functions wouldn't
like exceptions because, if you have to throw and catch within the
same function, exceptions seem messier than error returns.
>
> Want an exception on error? call Function.
> Want an error code? call function.
You are stuck with the standard libraries. Most of them return error
codes so there's no use crying about that. But your own functions,
written using the standard primitives can break the chain of
dependency.
Can you show an example of where needing to have both exceptions and
error codes was necessary?
Walt Howard
Sure.
> and whether errors can be ignored, handled locally, or only on a global
level.
I can't agree with that at all. For example, two ways to handle errors are 1)
to tell the user, and 2) to log the error silently.
Now, the exception itself could do 2) (i.e, the problem could easily be
handled locally), and some GUI code could do 1) (but
typically at a far remove from the call). But how is the library writer to
know which?
> Even for
> something as general as std::vector, it's a good bet that no
> application will be able to ignore bad_alloc, and even that no
> application will be able to handle it locally.
I wouldn't say "even for." The _reason_ why the exception cannot in general be
handled locally is because the module is so general.
> If, however, the library designer cannot know, the correct solution is
> a return code.
Which lends itself poorly to one of the choices (remote handling).
> Why should people who cannot use the exception pay its
> price (and I'm not talking only about performance, but the added
> complexity of writing a try/catch block)? For those who need the
> exception, of course, all it takes is a single if to get it.
However, I will agree that not _all_ returns should be exceptions. But library
code, it seems to me, should use them, because local
handling is trivial (even if verbose and/or awkward) and remote handling is
best accomplished this way.
Try a C++ object that represents a real world object. It can refuse
to change location when asked. The object remains in a valid state,
but the state is not what was requested. If the caller accepts that
a request may be ignored --- and that acceptance can be encouraged
through documentation --- then it does not need to be forced to handle
the case where the request is not acted on.
C and C++ I/O libraries do this sort of thing all the time.
For example, when fscanf() encounters an end of file, all
reading functions will return an error code. However, it is
not possible to corrupt the file system by attempting to
read past end of file [at least not portably].
>
> > 2) Those that the caller can handle immediately.
> > 3) Those that the caller can not handle immediately,
> > and must be passed further up the call chain.
> >
> > The first case is most suitable for implementation by return
> > codes. The third is most suitable for implementation using
> > exceptions. The second is suitable for either scheme depending
> > on context:
>
> Exactly. And the writer of a library can't know what that precise context
is.
IMHO, if the library writer does not know [or have a reasonable
indication of]
context, it is better to use a return code. That gives the caller a
choice of handling errors, but does not force handling conditions
that need not be handled.
There is nothing more irritating than being forced to explicitly catch
and discard a number of error conditions, when you don't need to handle
them.
>
> > > You're no more forced to handle exceptions than you are to deal with
> return
> > > codes. It's a little harder to ignore errors, but not impossible.
> > >
> >
> > I must be missing something. It is not possible to ignore exceptions.
> > It is possible to deliberately swallow an exception (eg catch it, do
> > nothing, and don't rethrow), but that is not ignoring the exception.
> > It is a deliberate action to prevent the exception propagating.
> > With error codes, doing nothing is a default choice (i.e. unless
> > you choose to handle it, it is ignored).
>
> Semantics. By "ignore" I was talking about wrapping a function in a
try/catch
> that ignores the result.
>
Semantics is rather important in this context, as they affect how people
interpret what is said.
> The technique of combining a return status and a return value has
> been known a long time - I'm sure its mentioned in Barton and
> Nackman (1994?).
Barton and Nackman describe a "Fallible" template class, which
associates a value of an arbitrary type and a bool. Accessing the
value when the bool is false results in a run-time error (an assertion
failure in Barton and Nackman and in my implementation).
As presented, I don't think this is exactly what we are thinking of.
IMHO, it is mainly for cases like look-up functions, where "failure"
is more or less expected, and will normally be for a well known
reason. It's very useful, but it doesn't transport any additional
information about the failure.
It would not be too difficult to extend it, using the Flyweight
pattern, to contain arbitrary additional failure information. In
practice, my designs tend to separate data acquistion functions, which
have a return value, and if they fail, it is in a known way, and
functions which "do something", and whose only return value is an
error code. The standard implementation of Fallible is perfectly
adequate for the first, and a different ReturnCode class handles the
second. With regards to the first, I've found it useful to extend the
Fallible class with an "elseDefaultTo" function: f.elseDefaultTo(x)
returns the value of f if it is set, otherwise x; I think that the
utility of such a function is indicative of the sphere of application
of Fallible.
> It goes something like (cut and paste from an internal API I'm
> working with):
> template<typename rtype>
> class status_return
> {
> public:
> typedef rtype return_type;
> /// Default construct a successful return
> status_return();
> /// Construct a successful return
> status_return(return_type value);
> /// Construct a mixed return (usually a warning)
> status_return(status exit_status, return_type value);
> /// Construct an unsuccessful return
> status_return(status exit_status);
> /// Converts to "true" if (and only if) status_success/warning.
> operator bool() const;
> ///
> const status& get_status() const;
> ///
> const return_type& get_value() const;
> // . . .
> };
> IIRC James has posted a varient that makes a fuss at runtime if the
> status isn't accessed by the client code.
Not really a variant of this; just a simple return code. But the same
principle is easily adopted. The object contains a flag
"hasBeenRead", which is set to false in the constructor, and to true
in the function which reads the status. If it is false in the
destructor, there is a run-time error.
In practice, I would make this field mutable, and set it to true when
the object is copied (copy constructor or assignment, both of which
copy the old value to the destination object).
--
James Kanze mailto:ka...@gabi-soft.de
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
Ziegelhüttenweg 17a, 60598 Frankfurt, Germany Tel. +49(069)63198627
> "Robert O'Dowd" <nos...@nonexistant.com> wrote in message
> news:3A400E14...@nonexistant.com...
> > The designer of a library usually has some sense of likely use
> > cases. Otherwise, there would be no requirement for the library
> > in the first place. Errors that get reported to a caller will
> > fall into three (for sake of discussion) distinct categories.
> > 1) Those that can be safely (or optionally) ignored.
> I'm having trouble coming up with an example of this. In COM, it's
> possible for a function to "succeed with information", but I
> certainly haven't seen much need to do that.
I've needed it once. Basically, we were writing to a mag tape; if
retries were needed, the write still succeeded, but we wanted to
inform the operator so he could retire the tape when finished with
these data, rather than recycling it for the next set of data.
--
James Kanze mailto:ka...@gabi-soft.de
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
Ziegelhüttenweg 17a, 60598 Frankfurt, Germany Tel. +49(069)63198627
> > Why should people who cannot use the exception pay its
> > price (and I'm not talking only about performance, but the added
> > complexity of writing a try/catch block)? For those who need the
> > exception, of course, all it takes is a single if to get it.
> However, I will agree that not _all_ returns should be
> exceptions. But library code, it seems to me, should use them,
> because local handling is trivial (even if verbose and/or awkward)
> and remote handling is best accomplished this way.
Which is where we disagree. When in doubt, I find it wrong to force
the cost of exceptions on code which doesn't need them. It's easy to
wrap a function, to convert a return code to a throw. But once
something is thrown, you've paid the cost.
--
James Kanze mailto:ka...@gabi-soft.de
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
Ziegelhüttenweg 17a, 60598 Frankfurt, Germany Tel. +49(069)63198627
> I would do
With an added if before the processing:-).
Most of the time, I just wrap foo:
bool
myFoo()
{
bool result ;
try {
foo() ;
result = true ;
} catch ( ... ) {
// Log error, maybe attempt alternatives...
result = false ;
}
return result ;
}
or something similar. Most of the time, in practice, foo will return
an object; what I want is null when it fails. Which gives the
following:
MyType*
myFoo()
{
MyType* result = NULL ;
try {
result = foo() ;
} catch ( ... ) {
}
return result ;
}
Somehow, the fact that my code contains so many empty catch blocks
makes me uneasy.
This is also similar to the way I handled errors in constructors
before exceptions:
MyType*
createMyType()
{
MyType* result = new MyType() ;
if ( ! result->initialize() ) {
delete result ;
result = null ;
}
return result ;
}
Null pointers are singular value guaranteed by the standard.
--
James Kanze mailto:ka...@gabi-soft.de
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
Ziegelhüttenweg 17a, 60598 Frankfurt, Germany Tel. +49(069)63198627
--
James Kanze mailto:ka...@gabi-soft.de
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
Ziegelhüttenweg 17a, 60598 Frankfurt, Germany Tel. +49(069)63198627
> James...@dresdner-bank.com (James Kanze) wrote (abridged):
> > The problem is that normally, you want to handle the problem
> > immediately, before going any further. You don't want the error to
> > propagate up. There are certainly special cases, where the
> > impossibility of opening a file should result in aborting the
> > current operation, but they are generally rare.
> Maybe this depends on the application. In the kind I have worked on,
> the file name would come from a user-interface and would typically
> be picked from a list of existing files. For it not to exist would
> imply it disappeared between the picking and the opening. This is
> certainly rare enough to be considered an exception.
Curiously enough, I rarely read directly from a file -- input data
comes either from a GUI, or more often, a data base, or another
machine. I do write to files, however. Mostly for logging and such,
in which case, errors are just ignored.
One can easily exterpolate the problem to reading a record from a data
base, however. First, I connect to the data base during
initialization. The normal GUI isn't yet available. So I pop up a
window, with abort/retry buttons. Practically in the routine which
does the connection. (The entire retry loop is less than 10 lines of
code. The actual popup is handled by a maybeFatalError routine, which
is used by all of the initialization steps.)
Afterwards, the record key is read by a function which displays a
dialog on the GUI, then gets the record, and returns it. In case of
error, it returns null. Whoever called the routine knows what to do
when the data set isn't available.
(This is a radical simplification. In the actual application, the
situation is significantly complicated by the fact that the data base
access requires network access, involves delays, and thus cannot be
done in the thread which handles the dialog. Of course, this is
another problem with exceptions; they don't propagate across thread
boundaries.)
> I don't see how the code can resolve the problem locally. It
> typically means going back to the UI to ask for another name. The
> code that opens the file can't very well do this itself as it should
> be decoupled from the UI. Throwing an exception seems very natural
> here.
See above. The interface to the entire dialog returns the data set,
or null. It could easily be modified to continue the dialog in case
of failure. But it must be able to propagate a failure out -- simple
ergonomics requires that the user be able to abort any dialog. The
data set access is triggered by a GUI event -- in the Java case, it is
an inner class which simply calls a function in my main display class.
> Whatever - the Java situation is made worse, in my view, by the fact
> that the FileNotFoundException is a declared exception. This means
> it must either be handled explicitly or propagated
> explicitly. Detailed "throws" clauses tend to spread through the
> call tree, and have to be updated when methods change. This is extra
> work for no real benefit. Worse, it gives a false sense of security
> because people imagine they only have to deal with the declared
> exceptions and forget about the undeclared ones. In reality, almost
> any routine can throw an exception because almost any routine may
> try a memory allocation.
Actually, I sort of favor checked exceptions. Changing the possible
exceptions a function can throw is a change in the contract, and it is
nice if the compiler could verify it. I also understand the problems
involved in this, however, and why C++ chose a different approach.
Both are defensible.
What isn't defensible, of course, is mixing the two approaches, as in
Java. In practice, you never know what exceptions a Java function
might throw, so you don't have the benefits of compiler checking of
the contract, but you still have to go through the effort of declaring
it for certain cases. The disadvantages of both. (To be fair, the
original idea seems to have been that only exceptions that almost any
function might throw, like insufficient memory, would be unchecked.
In practice, however, the availability of unchecked exceptions means
that when someone does want to add an exception to an existing
interface, they usually try and find an unchecked exception that "sort
of" fits, so they can avoid having to document the change in the
contract and telling others about it. The result is all of the
advantages of checked exceptions fly out the window, and you are left
with just the disadvantages.)
> In C++ exceptions are much less intrusive. Most C++ code needs only
> to know that an exception is possible and doesn't care what it
> is. The only useful exception specification is an empty one.
In general, the most useful (and essential) information is whether or
not a function can throw. In some ways, it is regrettable that the
default is that the function can throw anything. But at least I have
the possibility to say that it throws nothing.
--
James Kanze mailto:ka...@gabi-soft.de
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
Ziegelhüttenweg 17a, 60598 Frankfurt, Germany Tel. +49(069)63198627
> Daniel James <inte...@nospam.demon.co.uk> writes:
> > Another issue was debuggability, if there's only one return it's
> > easy to put a breakpoint on it, if there are several its easy to
> > overlook one and find that the function you were debugging has
> > returned through a path you'd forgotten about - and all of its
> > local variables have gone out of scope so you can't tell why. This
> > issue is now largely academic because most good debuggers will now
> > accept a breakpoint on the closing brace of a function so that it
> > will be triggered by any return from within the function.
> > We have the same problem with exceptions, though. If a function
> > can throw from numerous places it's hard to breakpoint them all.
> Uh, no. It's much easier to set breakpoints with exceptions. Since
> an exception is an object, it has a constructor and you can catch
> every throw of that object with a breakpoint in its constructor.
If you want to set a breakpoint anytime you leave a function,
exceptions make it more difficult, since you no longer have just a
single return at the end of the function. (I'm supposing that you
don't want to necessarily break when some nested function throws.
Only when the exception propagates up to your function, so you leave
it.)
Setting a breakpoint in the constructor of the exception is no
different than setting a breakpoint in the constructor of the error
descriptor of a return code. Where exceptions may make things easier
is the possibility of setting a breakpoint in the compiler run-time
routine that does exception handling, in order to break anytime any
error is detected.
--
James Kanze mailto:ka...@gabi-soft.de
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
Ziegelhüttenweg 17a, 60598 Frankfurt, Germany Tel. +49(069)63198627
My recent experience is with a project that uses a number of libraries, each of
which throws its own type of exception object. Not only would I have to breakpoint
the constructors of *all* the exception types, I would also have (somehow?) to
breakpoint the constructors of exception classes for which I don't have sourcecode
or debugging information. One of the exception types involved has an inline
constructor, and that doesn't help, either!
Cheers,
Daniel
[nospam.demon.co.uk is a spam-magnet. Replace nospam with sonadata to reply]