However, Scott Meyers urges caution when using exception
specifications, because if your class throws an unexpected exception,
(and you haven't specified std::bad_exception), clients can't use a
catch-all exception handler. But then again, they can use
std::set_unexpected() to overwrite the unexepcted() function to throw
something.
So what are everyone's thoughts on exception specifications? When
should they be used? Who has used exception specifications
extensively? How did they work out?
Any advice, anecdotes from experience, or comments would be
appreciated.
--
Steve Molitor
smol...@erac.com
"Emacs is the Computer"
[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]
[ about comp.lang.c++.moderated. First time posters: do this! ]
[Stroustrup, 1997] 14.11 Advice
[15] Use exception-specifications for major interfaces; 14.9
I say, let users override the global hooks if they want to catch-all.
--
Marc Lepage
Software Developer
Molecular Mining Corporation
http://www.molecularmining.com/
If your clients are happy with programs suddenly terminating, then go
ahead. Otherwise I wouldn't touch exception specifications with a ten-foot
pole. The only, hm, well, exception I would perhaps make are throw()
specifications for functions that don't call any other functions.
When your library throws an unexpected exception, there must be some
logical error. Being alerted to it may be of value to you, but I doubt it
would be to your client, especially considering that he has to go through
the extra trouble of overriding unexpected(). People will either forget it,
in which case their programs will terminate, or they will get an exception
- something that they would have got anyway if you hadn't bothered with
exception specifications in the first place.
Gerhard Menzl
The problem with exception specifications is that the
compiler/run-time system don't give you any help to enforce
them except for aborting your app in case it breaks one.
This is almost never a usefull approach and needs to be
prevented, but I wouldn't even think of putting the burden
of dealing with this onto the users of your code. IMO it's
your task to install an unexpected handler when entering
a function with exception specifications. (This handler
would then throw a valid exception instead.)
You can make sure that users are able to catch all your
exceptions without thinking to much about it by deriving all
your exceptions from one base class. Users can then simply
catch this class and get everything they need. Exception
specifications can still be very usefull in order to make
sure no other excepions (of 3rd party code you use) escape
from your code, but the main point is: This is your task,
not your user's task. (Although it seems a lot easier to
produce meaningfull error messages when you catch exceptions
explicitly instead of using unexpected handlers where you
have no portable way of finding out about the exception
thrown.)
> Steve Molitor
Schobi
Not quite ... if your class *promotes* ... this means if some member
functions calls some other member function which calls some
std::function which throws an std::out_of_range() exception, then
the whole thing is free to go south if std::out_of_range() is missing
in your exception specification.
In short that means you either need to specify every exception in
your exception specification, can become quite a mouthful, or your
application is going to crash on site one day (the user does not
care, to him or here it will be a crash).
>So what are everyone's thoughts on exception specifications? When
>should they be used? Who has used exception specifications
>extensively? How did they work out?
Think it over thrice; I did and in the end restricted myself to
throw() where it made sense. Just think of an exception specification
listing almost all standard exceptions plus the application specific
ones. It could become longer than the whole function; add some comments
and you´re in for the "where´s the code" game.
But in the end it is like all the other features, try and see whether
it works out for you and if not, then feel free to leave them and
ignore those "I told you so"´s.
Cheers,
Juergen
--
\ Real name : Jürgen Heinzl \ no flames /
\ EMail Private : jue...@monocerus.demon.co.uk \ send money instead /
I've used exception specs. extensively in several libraries I've
developed for exactly the same reasons you mentioned in your
first paragraph, with very positive results.
I haven't had any problems with unexpected exceptions. If anything,
I think they're useful for debugging purposes. I set the unexpected
handler up to do something distinguishable from the program's
catch-all so I can easily determine whether a library has thrown an
undocumented error or whether the program has encountered an
error that it (in most cases) should catch elsewhere.
I think that this is one (and not the only one) of those features that the
committee invented without having a full understanding of the consequences,
an understanding that could be gained only with experience using the
feature. (Only guessing here, and not meaning to start a flame war.) I'd
also guess that they would have preferred to do it differently, but the
design they wound up with was the only one that does not compromise legacy
code. The ultimate rationalization for the design seems to be, "if you don't
like it, don't use it."
I forgot where I read it (might have been Stroustrup), but I though a pretty
good take on exception specifications is:
Use them, but disable them in the release build. They can be helpful in
terms of coding discipline and to find logic errors during development, a
time where a program termination because of logic errors is good. Then the
release build disables them, thus there is no danger to the end user app.
You must wrap them in a macro to achieve this, which turns into an empty
macro in the release build (similar to assert).
Jan
If a library throws an exception that isn't documented, then a user of
that library is going to have problems regardless. The exception can
be caught by a catch-all block, but that doesn't help the user
determine the problem. At least an overriden unexpected handler
allows the user to distinguish between exceptions he should be
catching and exceptions that are undocumented.
I've been using exception specs. in three significant libraries for
over a year, and using them has improved both the libraries and
client applications.
I use them whenever I have a situation where I don't want the program to
continue, and don't trust another programmer to pay attention to a return
value.
In the project I'm working on now, exceptions are responsible for reporting the
mostly fatal errors from a 3rd-party library and makes its error messages
available through err.what(). I usually derive from std::runtime_error for
consistency.
The C++ Committee did not invent exception specifications. They are in
the ARM (p 361ff). The committee chose not to remove them from the
language definition.
--
Steve Clamage, stephen...@sun.com
In my opinion, all things associated with exception handling are committee
inventions (or innovations?), first because the ARM specifies them as
experimental language features, and second because X3J16 convened in 1989
whereas The ARM was published the following year and is identified on its
cover as the "ANSI Base Document."
Exception handling was not widely (or even very thinly) available prior to
the work of the committee getting underway after which compiler vendors
began to include early versions of the feature. The first implementations
that most of us saw of exceptions did not include exception specifications,
if I remember correctly.
Given all that, it is not unreasonable to treat anything that the ARM
invents as a committee invention, in my opinion. If that is not the
generally accepted attitude, however, I willingly yield the point.
I don't see what the advantage of unexpected() over catch(...) is. On the
contrary: both tell you that an unexpected exception has occurred, but at
the point the catch-all handler is entered at least the stack has been
unwound, and the application can shutdown gracefully. This is much more
difficult (if not altogether impossible) with a global error handler that
is called completely out of context.
> I've been using exception specs. in three significant libraries for
> over a year, and using them has improved both the libraries and
> client applications.
Interesting. I'm curious as to what the implementation of unexpected() in
your client application looks like. Do you abort or throw a meta-exception?
A main reservation I have about exception specifications is
maintainability. A change of implementation in a frequently used function
can require hundreds of interfaces to be modified. This might be a good
thing if it could be checked at compile time, but the problem is that
violations of exception specifications will not be detected until runtime.
In my view, this is against the spirit of C++ as a statically typed
language in which the compiler is supposed to find as many errors as
possible.
I think the usefulness of exception specifications depends on the type of
application. If it's a non-interactive, batch-type application, such as a
command line compiler, aborting may be acceptable. With an interactive GUI
program, such as a word processor, this is clearly out of the question.
Gerhard Menzl
Release mode or not, I don't see any advantage in having my app
aborting due to a call to unexpected over aborting due to an
uncaught exception.
As said in another post, the only argument for using them I see
would be if you want to assure that no 3rd party exception escapes
your code. But even then explicitly catching is better most of the
time.
Schobi
Excuse me, but as I understand it J16 & WG21 had absolutely nothing to
do with the writing of the ARM, they were told by those responsible that
it (together with the C Standard) was the basis on which they were to
start work. I think you will also find that the publication date of the
ARM was just that, the manuscript was already in existence in 1989 and
contained nothing that was strange to AT&T Research. In effect AT&T and
their employees were responsible for the original specification of C++.
Francis Glassborow Journal Editor, 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
That is, of course, the catch 22. Without ES exception correctness is
hard to check, but with it and without compilers and tools to check them
it adds nothing. That is why I would like to see compilers come with
switches to turn on/off ES's. It is a pity that we felt unable to
mandate something like NDEBUG.
Your historical perspective is not correct.
The organizing meeting of J16 (lasting one day) was in December 1989.
It consisted of ratifying the statement of work and setting the date
of the first real meeting. The ARM was in press at the time, if not
already published. (Books published after the middle of a year often
bear a publication date of the following year. I don't know whether
that was the case with the ARM.)
Drafts of the ARM had circulated to some of the people who became
active committee members. The material on exception handling had
previously appeared in papers published by Stroustrup. The first J16
technical meeting was in March 1990. The ARM was adopted as a
base document at that meeting. No language constructs were invented
at that meeting.
The exception model in the standard, including the definition of
exception specifications, does not differ by much from what
Stroustrup developed prior to the first J16 meeting.
--
Steve Clamage, stephen...@sun.com
I've decided to forgoe exception specifications, except in rare
instances where I really do want to abort if a bad exception is
thrown. I haven't identified any such instances yet.
Again, thanks for all the help.
--
Steve Molitor
smol...@erac.com
"Emacs is the Computer"
[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]
You're excused, but I didn't say that they did. I guess I'm not so willing
to yield, after are. The ARM and standardization are closely
related--inseparable, in fact. Stroustrup told me about the as-yet
unpublished ARM, a "book for experts," in an interview in June of 1989. He
also said, "We've been talking about exception handling and parameterized
types for a long time. It's universally agreed that we need them. We have a
reasonably good design for parameterized types that I presented at the last
USENIX C++ conference, and that needs to be refined a little bit. Exception
handling is one stage behind that, but we need it badly." As of that date EH
was not available anywhere.
Stroustrup went on to say, "Clearly we would like a fully standardized
language, and equally clearly we don't know how to do that. There are still
some features that we need to design. ...If we standardized C++ simply as it
was, everybody would build their own exception handling and parameterized
types." That says to me that he intended for his experimental features to be
examined, improved upon, and ratified by the committee.
>they were told by those responsible that
>it (together with the C Standard) was the basis on which they were to
>start work. I think you will also find that the publication date of the
>ARM was just that, the manuscript was already in existence in 1989
Stroustrup indicated that it would be completed in December, 89 or January,
90. He said, "The question is whether I can make it."
The ARM was the base document, it describes things that were not available
in commercial compilers, called them "experimental," and the committee
accepted those "inventions" and expanded upon them. We're splitting hairs,
but I am comfortable with my conclusions. It's just that for a long time,
Stroustrup was the sole charter member of that committee.
>Your historical perspective is not correct.
See my answer to Francis; I believe it is more correct than you are giving
credit for.
>(Books published after the middle of a year often
>bear a publication date of the following year.
Almost always. It's a common publisher trick to make books seem newer than
they are, although I thought you could do that only if the book came out in
the fourth quarter.
> I don't know whether that was the case with the ARM.)
It was not. The ARM was published in May of 1990, well after its content was
adopted by the committee. That's why they could put the "ANSI Base Document"
banner on the cover. Exception handling was accepted at the Palo Alto
meeting in November.
>The ARM was adopted as a base document at that meeting. No language
constructs were invented at that meeting.
Except by default those language constructs (templates and EH) that the ARM
invented.
> In article <385DF0DD...@sea.ericsson.se>, Gerhard Menzl <gerhard.m
> en...@sea.ericsson.se> writes
>>In my view, this is against the spirit of C++ as a statically typed
>>language in which the compiler is supposed to find as many errors as
>>possible.
>
> That is, of course, the catch 22. Without ES exception correctness is
> hard to check, but with it and without compilers and tools to check them
> it adds nothing.
The type of exception being thrown makes no difference whatsoever to 99.99%
of user code in a small project, and the ratio becomes sharper as the
project grows. Thus, only a very small amount of code need be affected by
the appearance of an unanticipated exception type, and the impact of that
appearance can be limited to making the details of the error opaque: so you
get "unknown error" instead of "out of memory". That's bad, but not
terrible. If the program can recover from "out of memory" it probably can
also recover from "unknown error", so the user is way ahead of where he'd be
if terminate() had been called.
A more accurate statement would have been: "without static ES checking, you
can't be quite as sure you'll get an accurate report about the cause of
every error". The way to think of static ES checking, and not having it, is
to imagine that you were using integer error return codes instead. What if
someone returns an error code for which you don't have an error message?
There is, of course, one sure way to ruin the nice property that in most
code, the type of exception being thrown doesn't matter: start using
exception-specifications ;)
-Dave
> >The C++ Committee did not invent exception specifications. They are in
> >the ARM (p 361ff). The committee chose not to remove them from the
> >language definition.
>
> In my opinion, all things associated with exception handling are committee
> inventions (or innovations?), first because the ARM specifies them as
> experimental language features, and second because X3J16 convened in 1989
> whereas The ARM was published the following year and is identified on its
> cover as the "ANSI Base Document."
>
> Exception handling was not widely (or even very thinly) available prior to
> the work of the committee getting underway after which compiler vendors
> began to include early versions of the feature. The first implementations
> that most of us saw of exceptions did not include exception specifications,
> if I remember correctly.
>
> Given all that, it is not unreasonable to treat anything that the ARM
> invents as a committee invention, in my opinion. If that is not the
> generally accepted attitude, however, I willingly yield the point.
I don't think that's right. By normal standards, I can claim the credit and
must take the blame for constructs that I invented and work I published -
even if it took a vote by a committee to make it into an international
standard. This includes exceptions and templates.
I think exception handling is a simple case here. I did indeed not implement
the exception handling mechanisms, but the standard closely follows my
documented design. The major difference between ARM exceptions and ISO C++
exceptions is (IMO) a slightly better compile-time checking of exception
specifications - that allows the compiler to reject programs at compile
time that I had left to be caught at compile time.
Templates evolved further during the standards process that exceptions did.
Like the rest of the features described in the ARM, the "experimental"
features (templates and exceptions) were first voted in as described and
then improved. If I recall correctly, voting in the "experimental" features
were among the earliest actions of the committee.
(Drafts of the ARM was available before the committee convened and "academic"
papers discussing exceptions and templates were published and presented at
conferences a year or two before).
- Bjarne
Bjarne Stroustrup - http://www.research.att.com/~bs
You are in an enviable position. You can indeed take the credit--you laid
the groundwork--but you need not take the blame; the work was subject to
review, modification, and approval or disapproval by a formally convened
body of expert language standardizers.