[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
To implement exception (or error) save code you need some functions to
recover from errors where you must be sure that they can not run into an
error condition again.
regards
Torsten
I feel C++ standard committee has its problem to solve. Being a user,
I am smart enough (probably not enough) avoid digging these issues.
Experts teach their experience at that time (may trim their words
latter as the standard may interpret as well), users are on their
own. throw() is necessary for some fundamental library functions, but
the real implement code may be empty.
> What is the rationale behind their decision?
>
It is that exception specification exists first, then the experts
feel it is bad and teach people to avoid, then the 3rd user confuses.
Exception specification is, for I know, to provide compile time check
and optimization.
What the experts have said about exception specs, was said long after
the C++ standard was completed (1998). Much has been learned since
then.
To anyone that knows: in C++200x, are changes being contemplated to
exception specs? What's being considered?
That's news to me. I know that a number of experts don't like
general exception specifications, but I don't think that there
is a consensus that throw() (to say that a function doesn't
throw) is bad.
> So, why has the committee decided to supply some standard
> functions with exception specifications? What is the rationale
> behind their decision?
Several reasons. One, the standard was written before the
experts came to their conclusion. Also, the standard is
defining interfaces, not actual implementations. Regardless of
the merits of exception specifications in compilable code, they
are a readable convention for specifying to a user which
exceptions a function might throw.
--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
Actually throw() does not say a function doesn't throw. It more or less asks
the compiler to add implicit catch statements to ensure the function does
not throw (and if the function does, those statements terminate the
program). This is not exactly what one would expect and that's why it is not
such a good thing.
--
JS
> > That's news to me. I know that a number of experts don't
> > like general exception specifications, but I don't think
> > that there is a consensus that throw() (to say that a
> > function doesn't throw) is bad.
> Actually throw() does not say a function doesn't throw. It
> more or less asks the compiler to add implicit catch
> statements to ensure the function does not throw (and if the
> function does, those statements terminate the program). This
> is not exactly what one would expect and that's why it is not
> such a good thing.
It depends from which side you are looking at things. As a
client, the presence of throw() very definitly does guarantee
that I will not get an exception from the function. That sounds
exactly what I would expect.
For that matter, when implementing the function, it means that I
am not allowed to leave the function by an exception (unless I
really do want to terminate the program brutally). That's
really what I would expect, too -- throw() means that I'm not
allowed to leave the function via an exception.
The fact that it results in an abort is in some ways a bit
strange. Most of the time, when I do something that isn't
allowed (e.g. dereference a nul pointer), I get undefined
behavior (although typically, on my implementations, the program
also terminates abnormally). But I'm not one to argue in favor
of adding undefined behavior.
I'm just curious: what do you expect it to mean which is
different?
--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
[Throwing from a function which is marked "throw()"]
>The fact that it results in an abort is in some ways a bit
>strange. Most of the time, when I do something that isn't
>allowed (e.g. dereference a nul pointer), I get undefined
>behavior (although typically, on my implementations, the program
>also terminates abnormally). But I'm not one to argue in favor
>of adding undefined behavior.
>I'm just curious: what do you expect it to mean which is
>different?
While I realize that this is insanely difficult, it would be
be *so* nice if it meant "This function won't compile if it
is capable of throwing an exception." I think that's a common
intuition for what it means, just as if you violate const-
correctness you don't get abnormal termination or undefined
behavior, you get a program that flatly doesn't compile.
I guess there are two awful problems with this, the first being
that it's very hard for the compiler to prove a function can't
call an exception, and the second being that sometimes the
programmer can prove it in a case where the compiler can't,
and we would like to be able to mark such functions "throw()".
Mary Kuhner mkku...@gs.washington.edu
I don't think it would be very good. You'd soon find yourself in a
position in which every one of your functions has to take into account
all the exceptions that might be thrown by the functions it calls. For
a device designed to allow error notification across nested calls I'd
consider this a major drawback.
> I guess there are two awful problems with this, the first being
> that it's very hard for the compiler to prove a function can't
> call an exception, and the second being that sometimes the
> programmer can prove it in a case where the compiler can't,
> and we would like to be able to mark such functions "throw()".
This is actually not very difficult: you make it an error for a
function with a throw() exception specification to either contain throw
statements or calls to functions that do not have the same
specifications.
Cheers,
Nicola Musatti
Why wouldn't this be very good? Isn't it the situation that if your
function has an exception specification, and a function it calls
happens to throw an exception which isn't in your specification, then
you'll get a (more or less) fatal runtime error anyway. How is it a
drawback for this to be detected at compile time rather than run time?
For those of use who write systems where crashing is not acceptable, we
can't use exception specifications, because of this (IMHO insane)
behaviour, even though we would like to.
To allow error notification across nested calls, you have to use no
exception specification, or specify all possible exceptions (or a
common base class which would be quite sensible), or risk your program
dying horribly.
> > I guess there are two awful problems with this, the first being
> > that it's very hard for the compiler to prove a function can't
> > call an exception, and the second being that sometimes the
> > programmer can prove it in a case where the compiler can't,
> > and we would like to be able to mark such functions "throw()".
>
> This is actually not very difficult: you make it an error for a
> function with a throw() exception specification to either contain
throw
> statements or calls to functions that do not have the same
> specifications.
That would be so nice... (but I think you'd have to make extern "C"
functions implicitly throw(), and of course, destructors should be
implicitly throw() anyway).
[ ... exception specification of 'throw()' ]
> While I realize that this is insanely difficult, it would be
> be *so* nice if it meant "This function won't compile if it
> is capable of throwing an exception." I think that's a common
> intuition for what it means, just as if you violate const-
> correctness you don't get abnormal termination or undefined
> behavior, you get a program that flatly doesn't compile.
This would correspond pretty closely with what Java calls a checked
exception. While it initially looks like a good idea to many people, it
doesn't seem to work out that way in practice (at least as a rule). If
you Google for "Java checked exception", you'll find quite a few papers
about the problems they cause.
> I guess there are two awful problems with this, the first being
> that it's very hard for the compiler to prove a function can't
> call an exception, and the second being that sometimes the
> programmer can prove it in a case where the compiler can't,
> and we would like to be able to mark such functions "throw()".
Actually, it's not all that difficult for the compiler to do: it
basically proves that this function doesn't use throw directly (pretty
trivial) and that if it calls a function either 1) that function
doesn't throw either (in the same way), or 2) anything it throws will
be caught and not re-thrown.
That would clearly add some complexity to the compiler, but I'm pretty
sure if it was required in C++, it wouldn't be anywhere close to the
most difficult/complex part of the compiler. OTOH, given the problems
they seem to cause, I'm glad it's not a required in C++.
--
Later,
Jerry.
The universe is a figment of its own imagination.
> How is it a
> drawback for this to be detected at compile time rather than run
time?
> For those of use who write systems where crashing is not acceptable,
we
> can't use exception specifications ...
I assume that you also don't use signed integer arithmetic, because the
compiler usually can't tell if it will invoke UB, and you also don't
use local variables, because the compiler can't tell if they will cause
stack overflow, ...
In some circumstances it might be nice to have a compiler that tells me
when it notices that
int i = rand();
++i;
might overflow or exceed the available stack space, but somehow I
suspect that I'd turn off those warnings, unless they were restricted
to cases where the compiler was pretty sure there was a problem.
If you're going to use C++, you're probably going to do a lot of things
that the compiler can't prove are safe. If you want to prove your code
is safe, you'd better use another set of tools.
> Mary K. Kuhner wrote:
>
> [ ... exception specification of 'throw()' ]
>
>> While I realize that this is insanely difficult, it would be
>> be *so* nice if it meant "This function won't compile if it
>> is capable of throwing an exception." I think that's a common
>> intuition for what it means, just as if you violate const-
>> correctness you don't get abnormal termination or undefined
>> behavior, you get a program that flatly doesn't compile.
>
> This would correspond pretty closely with what Java calls a checked
> exception. While it initially looks like a good idea to many people,
> it doesn't seem to work out that way in practice (at least as a
> rule). If you Google for "Java checked exception", you'll find quite
> a few papers about the problems they cause.
What Mary is talking about, though, is a simple "can throw/can't
throw" distinction. Most of us (even hard core
exception-specification critics like me) think this wouldn't cause
nearly the same kinds of problems, and might even be a huge win if
destructors were automatically marked "can't throw" unless otherwise
specified. It certainly would allow some optimizations that currently
are only possible if you use throw() everywhere it's possible.
--
Dave Abrahams
Boost Consulting
www.boost-consulting.com
I like this idea (*optionally* specified throw specifications) a lot,
but I don't think C++ has the proper tools to make this usable. While a
flow analysis program can use brute force to prove if a C++ function
would ever throw, analyzing all 8^32 (now 8^64 with 64 bit cpus) states
is impractical.
For the throw specifications to be able to be practically checked at
compile time, you'd need to be able to tell the compiler when a function
doesn't throw with finer granularity than function calls. I'm
envisioning a more granular type system, where you could say:
sqrt is a function that maps positive integers to positive integers,
zero to zero, and negative numbers to exceptional situations.
Then, if it could be proven that sqrt is only called with non-negative
numbers in a particular function (possibly because it asserts that it
will only be passed numbers in the range 0 to 100), then that function
will not throw because of sqrt.
The major disadvantage I see of a system like this is the sheer amount
of extra crap I have to type. Much like what's happening with const
correctness, I highly doubt that most projects would put enough work
into using such a system to see any benefit. Not enough common errors
are caught with this system for it to be psychologically pleasing.
-- MJF
> Actually, it's not all that difficult for the compiler to do: it
> basically proves that this function doesn't use throw directly (pretty
> trivial) and that if it calls a function either 1) that function
> doesn't throw either (in the same way), or 2) anything it throws will
> be caught and not re-thrown.
What about the case when a function calls a function that can throw, but
does so in such a way that it won't? For example:
void f()
{
if (some_complex_error_checking() == ALL_OK) {
g();
}
}
So g() might be declared to throw an exception but under these
particular circumstances the programmer might know that it won't in this
case. Thus the programmer can declare f() as not throwing any
exceptions. It would be hard for the compiler to figure this out.
It's my understanding that this is the main argument against static
checking of exception specifications. That is, if g() is declared to
throw an exception but f() is declared to throw none, the compiler would
complain about code that is actually perfectly acceptable. To keep the
compiler happy the programmer would have to add unnecessary try/catches
or declare f() to throw an exception he/she knows it won't.
Peter
[ ... ]
> What Mary is talking about, though, is a simple "can throw/can't
> throw" distinction. Most of us (even hard core
> exception-specification critics like me) think this wouldn't cause
> nearly the same kinds of problems, and might even be a huge win if
> destructors were automatically marked "can't throw" unless otherwise
> specified. It certainly would allow some optimizations that
currently
> are only possible if you use throw() everywhere it's possible.
While I have some misgivings, I can believe that might be worthwhile.
Then again, when exceptions were first introduced, I (along with
others, I'm pretty sure) wondered why lack of an exception specifiction
wasn't interpreted to mean "won't throw any exceptions". Since
exceptions hadn't previously existed (in C++), it was pretty clear that
existing code didn't throw any, so this would have basically just
codified existing practice.
OTOH, while I've previously heard people mention an empty excepction
specification as a win, I have to admit that I haven't encountered it
in practice, which may be part of the reason for my hesitation in
accepting the idea.
--
Later,
Jerry.
The universe is a figment of its own imagination.
As I understand it, the no-throw case is important in fairly rare pieces
of code that are explicitly about managing exceptions. The classic example
is two-phase assignment, which does a series of complicated statements
which may throw, followed by a series of simple ones which may not. Eg for
some user-defined class Vector:
Vector &Vector::operator=( const Vector &rhs ) {
Vector copy( rhs ); // May throw.
copy.swap( *this ); // May not throw.
return *this; // May not throw.
}
If we only care about no-throw in limited stretches of special code, the
problems become more manageable, because the solutions don't need to scale
so. For example, it'd be reasonable to split your g() into two functions,
one which can throw and one which can't. Let's say it is actually sqrt().
We could have:
double sqrt( double f ) {
if (f < 0)
throw "invalid arg";
return sqrt_nothrow( f );
}
double sqrt_nothrow( double f ) throw() {
assert( f >= 0 );
return ...; // Do the maths.
}
Then the caller can pick the no-throw version when they need it and can
take responsibility for ensuring its preconditions. We wouldn't want to
split every function like this, but functions which need a no-throw spec
are rare.
> To keep the compiler happy the programmer would have to add
> unnecessary try/catches
Again that's fine so long as it is rare. Hopefully the spurious try/catch
will have little or no run-time overhead if the exception is never
actually thrown.
> or declare f() to throw an exception he/she knows it won't.
In C++ that would be the default. It's the maintainable option in that the
implementation may need to change later so that it does throw.
Incidently, we really need no-throw blocks as well as no-throw routines.
Vector &Vector::operator=( const Vector &rhs ) {
Vector copy( rhs ); // May throw.
throw() {
copy.swap( *this ); // May not throw.
return *this; // May not throw.
}
}
or whatever the syntax might be.
-- Dave Harris, Nottingham, UK.
> David Abrahams wrote:
>
> [ ... ]
>
>> What Mary is talking about, though, is a simple "can throw/can't
>> throw" distinction. Most of us (even hard core
>> exception-specification critics like me) think this wouldn't cause
>> nearly the same kinds of problems, and might even be a huge win if
>> destructors were automatically marked "can't throw" unless otherwise
>> specified. It certainly would allow some optimizations that
> currently
>> are only possible if you use throw() everywhere it's possible.
>
> While I have some misgivings, I can believe that might be worthwhile.
>
> Then again, when exceptions were first introduced, I (along with
> others, I'm pretty sure) wondered why lack of an exception specifiction
> wasn't interpreted to mean "won't throw any exceptions". Since
> exceptions hadn't previously existed (in C++), it was pretty clear that
> existing code didn't throw any, so this would have basically just
> codified existing practice.
Oh, but that would've been awful for new code, because people would've
started writing fine-grained exception specifications everywhere.
Even those with the foresight not to would have had to write
throw(...)
which is a bit too verbose for my taste.
> OTOH, while I've previously heard people mention an empty excepction
> specification as a win, I have to admit that I haven't encountered it
> in practice, which may be part of the reason for my hesitation in
> accepting the idea.
On the best EH implementations, it saves a bunch of space in the
program image because you don't have to store unwind data, and it can
sometimes also improve the performance of non-EH code because there's
less register pressure.
--
Dave Abrahams
Boost Consulting
www.boost-consulting.com
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ ... ]
> > Then again, when exceptions were first introduced, I (along with
> > others, I'm pretty sure) wondered why lack of an exception
> > specifiction wasn't interpreted to mean "won't throw any
> > exceptions". Since exceptions hadn't previously existed (in C++),
> > it was pretty clear that existing code didn't throw any, so this
> > would have basically just codified existing practice.
>
> Oh, but that would've been awful for new code, because people
> would've started writing fine-grained exception specifications
> everywhere. Even those with the foresight not to would have had
> to write
>
> throw(...)
>
> which is a bit too verbose for my taste.
Looking at things, I see I edited my post a bit more than I should have
-- I originally had a sentence saying something like "OTOH, knowing
what I do now, I'm sure glad they didn't do what I would have at the
time."
[ ... ]
> On the best EH implementations, it saves a bunch of space in the
> program image because you don't have to store unwind data, and it can
> sometimes also improve the performance of non-EH code because there's
> less register pressure.
While it's easy to see how this would save space, I'm a bit lost on how
it would make any noticeable difference in register pressure, though
I'll admit I haven't spent a lot of time thinking about it. Worse, when
I'm looking at generated code, I normally use VC++, which has
sufficiently non-standard handling of exception specifications
(especially empty ones) that its output means nothing about what a
conforming compiler would do with the same code -- and in this case,
the basic nature of Comeau C++ keeps it from providing much help
either.
--
Later,
Jerry.
The universe is a figment of its own imagination.
There are circumstances where it is more acceptable for the system to
give incorrect information to one user than it is for the system to
give no information to any users because it has just crashed.
Where the compiler can detect that this is likely (paths through code
that leave variables uninitialised, not returning a value [appears to
have magically turned into an error in recent compilers], throwing an
exception not in the exception specification, throwing an exception in
a destructor, passing an integer when an enum is expected) why
shouldn't the compiler tell you? It is a waste of everyone's time when
this sort of errors gets into production software, when it is something
that the compiler could have detected.
I've seen more than one error which would have been caught by
prototyping functions, and there were enough complaints when that was
introduced to C by the standards body.
>
> In some circumstances it might be nice to have a compiler that tells
me
> when it notices that
> int i = rand();
> ++i;
> might overflow or exceed the available stack space, but somehow I
> suspect that I'd turn off those warnings, unless they were restricted
> to cases where the compiler was pretty sure there was a problem.
So you don't think the compiler could be pretty sure there would be a
problem in this code:
void func() throw (std::exception)
{
throw "Banana";
}
or
void func()
{
unsigned short x = 100000;
}
or even this
void func()
{
unsigned int i;
....
if (i < 0) ...
}
I've seen all those cause real problems in real code. You really think
the compiler shouldn't warn about those? Mistakes do happen, and a
compiler could check all of those trivially, saving much time further
on down the line.
> If you're going to use C++, you're probably going to do a lot of
things
> that the compiler can't prove are safe. If you want to prove your
code
> is safe, you'd better use another set of tools.
As you can't even prove that a Turing m/c will ever halt, I don't
expect a compiler to prove that your code is safe. That doesn't mean
there aren't situations where it can't easily detect that your code is
bound to invoke undefined behavior (or, in the case of exceptions,
extremely unhelpful behaviour).
And your example is not a good reason why something as easily
verifiable as an exception specification should not be checked.
Exactly. My point is not that I don't want exception specifications to
be checked at compile time instead of runtime; my point is I don't want
exception specifications period.
Cheers,
Nicola Musatti
Actually there would also have been an awful lot of old code as well,
every singly function that either directly or indirectly used a new
expression.
--
Francis Glassborow ACCU
Author of 'You Can Do It!' see http://www.spellen.org/youcandoit
For project ideas and contributions: http://www.spellen.org/youcandoit/projects
That code was broken anyway as soon as new started to throw exceptions.
--
Dave Abrahams
Boost Consulting
www.boost-consulting.com
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
> I like this idea (*optionally* specified throw specifications) a lot,
> but I don't think C++ has the proper tools to make this usable.
While a
> flow analysis program can use brute force to prove if a C++ function
> would ever throw, analyzing all 8^32 (now 8^64 with 64 bit cpus)
states
> is impractical.
>
> For the throw specifications to be able to be practically checked at
> compile time, you'd need to be able to tell the compiler when a
function
> doesn't throw with finer granularity than function calls.
No, that isn't necessary. A throw spec says "this function may throw
the following exceptions". A bit like not specifying a const pointer
says "this function may alter the data pointed to". It doesn't mean it
will, but its still 100% erroneous to pass a const pointer to something
that expects a non-const pointer. In the const case, the caller has
comitted to some client not to alter his data, and is passing the data
to a function that makes no such commitment. In the throw case, the
caller has made the commitment to the client he will only throw such
and such an exception, and is calling a function who makes no such
commitment. It is truly bizarre that this is checked at runtime, and
causes program termination, when it could be checked easily at compile
time and be fixed before bad things happen.
> I'm
> envisioning a more granular type system, where you could say:
>
> sqrt is a function that maps positive integers to positive integers,
> zero to zero, and negative numbers to exceptional situations.
Isn't this what the "design by contract" proposal addresses?
> Then, if it could be proven that sqrt is only called with
non-negative
> numbers in a particular function (possibly because it asserts that it
> will only be passed numbers in the range 0 to 100), then that
function
> will not throw because of sqrt.
You could implement sqrt using 2 functions (one which checks the
arguments and throws, one which dosn't check the arguments, and
assumes...) - see an earlier posting on this thread.
> The major disadvantage I see of a system like this is the sheer
amount
> of extra crap I have to type. Much like what's happening with const
> correctness, I highly doubt that most projects would put enough work
> into using such a system to see any benefit. Not enough common
errors
> are caught with this system for it to be psychologically pleasing.
You don't have to specify an exception specification, which roughly
translates as "I can, and will, throw anything I feel like". No
overhead to people who don't use exception specifications at all.
In so far as the original mechanism for dealing with 'out of memory' no
longer worked, but it was possible to just add a catch at some suitable
level (like main) and the program would carry on as before (unless it
ran out of memory) but once you have the default for es to be throws
nothing...
--
Francis Glassborow ACCU
Author of 'You Can Do It!' see http://www.spellen.org/youcandoit
For project ideas and contributions: http://www.spellen.org/youcandoit/projects
>Mary K. Kuhner wrote:
[compile-time exception specifications]
>> I guess there are two awful problems with this, the first being
>> that it's very hard for the compiler to prove a function can't
>> call an exception, and the second being that sometimes the
>> programmer can prove it in a case where the compiler can't,
>> and we would like to be able to mark such functions "throw()".
>This is actually not very difficult: you make it an error for a
>function with a throw() exception specification to either contain throw
>statements or calls to functions that do not have the same
>specifications.
Is this really all that easy, in the presence of polymorphism
and function pointers? For example, if Base::Foo cannot throw
but Derived::Foo can, am I allowed to call through a pointer-
to-Base-function? I guess you could make the rule that if
Base::Foo cannot throw, no Derived::Foo can either.
My second point, though, was that *I* may know that the
function won't throw, even if the compiler cannot know.
if (arg != 0.0) FuncWhichThrowsOnlyOnZero(arg);
Assuming that the function name is telling the truth, then this
line could be part of a "throw()" function quite safely. But
the compiler won't know that, short of an analysis it may
not be qualified to make. So compile-time enforcement of
"throws()" would greatly restrict the functions you could call
from a "throws()" function.
I suspect the eventual outcome would be no exception specs
anywhere. Which is not that different from what we have now,
to be honest.
Mary Kuhner mkku...@eskimo.com
>> Mary K. Kuhner wrote:
>> [ ... exception specification of 'throw()' ]
>>> While I realize that this is insanely difficult, it would be
>>> be *so* nice if it meant "This function won't compile if it
>>> is capable of throwing an exception." I think that's a common
>>> intuition for what it means, just as if you violate const-
>>> correctness you don't get abnormal termination or undefined
>>> behavior, you get a program that flatly doesn't compile.
>> This would correspond pretty closely with what Java calls a checked
>> exception. While it initially looks like a good idea to many people,
>> it doesn't seem to work out that way in practice (at least as a
>> rule). If you Google for "Java checked exception", you'll find quite
>> a few papers about the problems they cause.
>What Mary is talking about, though, is a simple "can throw/can't
>throw" distinction. Most of us (even hard core
>exception-specification critics like me) think this wouldn't cause
>nearly the same kinds of problems, and might even be a huge win if
>destructors were automatically marked "can't throw" unless otherwise
>specified. It certainly would allow some optimizations that currently
>are only possible if you use throw() everywhere it's possible.
Yes. I don't want the fact that a low-level routine in my
directed graph rearrangement subsystem can throw "too_many_migrations"
to have to be reflected in exception specs of every doggone
function all the way up to the catcher, eight levels above it.
So the full Java checked exception model is not going to work for
me. What I *would* like is for the compiler to be able to check
my statement that a certain function does not throw *at all*. This
would allow several things:
--using the function in a destructor
--using it in a strongly exception-safe idiom or context. For
example, being able to prove that your class implementation of
swap() does not throw would greatly aid using it in Herb's
"do the work on the side and then swap() it into place"
exception safety idiom.
I would be willing to have this work done by a separate tool
rather than the compiler, but at the moment I don't have such a
tool. I think in either case an important feature would be
the ability to mark a function as "non-throwing by programmer
fiat" even though it looks as though it can throw--analogous
to static_cast<> or reinterpret_cast<> to tell the compiler
"Just this once, I do know better than you do."
Mary Kuhner mkku...@eskimo.com
Since we're dreaming about statically-checked exception specs, why not
add an exception-spec cast, e.g.:
void f() throw()
{
if (some_complex_error_checking() == ALL_OK)
exception_cast< throw() >( g() );
}
The basic idea being that you can help the compiler out by telling it
that "g()" behaves as thow it were declared "throw()" in this case.
I'm guessing this is probably as dangerous as a reinterpret_cast in the
case where the programmer is wrong, but you could probably come up with
differing levels of casting, just like we have static_cast, dynamic_cast
and reinterpret_cast.
--
Early Ehlinger, President, www.ResPower.com, Home of the Super/Farmâ„¢ -
the 2.9+THz computer farm service.
[... That's right, THz, as in terahertz. As in thousands of GHz. As in
millions of MHz, billions of Hz. :^) ...]
>
> --using the function in a destructor
> --using it in a strongly exception-safe idiom or context. For
> example, being able to prove that your class implementation of
> swap() does not throw would greatly aid using it in Herb's
> "do the work on the side and then swap() it into place"
> exception safety idiom.
>
> I would be willing to have this work done by a separate tool
> rather than the compiler, but at the moment I don't have such a
> tool. I think in either case an important feature would be
> the ability to mark a function as "non-throwing by programmer
> fiat" even though it looks as though it can throw--analogous
> to static_cast<> or reinterpret_cast<> to tell the compiler
> "Just this once, I do know better than you do."
Think of the fun you'd have if that went wrong though. If you said
void func() throw()
{
Some_Rather_Complex_Class xclass; //Huge complex constructor &
destructor
//....code that couldn't throw an exception
exception_cast<throw()> wibble();
//... more code that doesn't throw exceptions
}
presumably the compiler will assume wibble() doesn't throw, won't put
any code into func() to catch exceptions (after all, that's the
optimisation you should make if all the functions you call are
throw()), and if wibble does throw an exception, it'll pass straight
into the caller of func, without calling the destructor of xclass.
That could be even more fun if func was actually a destructor.
> Mary Kuhner mkku...@eskimo.com
Tom
It is already illegal for a derived function to have a less restrictive
exception specification than its base class's one.
> My second point, though, was that *I* may know that the
> function won't throw, even if the compiler cannot know.
>
> if (arg != 0.0) FuncWhichThrowsOnlyOnZero(arg);
>
> Assuming that the function name is telling the truth, then this
> line could be part of a "throw()" function quite safely. But
> the compiler won't know that, short of an analysis it may
> not be qualified to make. So compile-time enforcement of
> "throws()" would greatly restrict the functions you could call
> from a "throws()" function.
>
> I suspect the eventual outcome would be no exception specs
> anywhere. Which is not that different from what we have now,
> to be honest.
Exactly.
Cheers,
Nicola Musatti
I just finished skimming over the Design by Contract proposal, and yes,
it does most of what I'd want. The one thing I find lacking is some way
to say "such-and-such implies this function is nothrow/const". Add this
in and it could represent everything I see myself wanting to represent.
-- MJF
Well, there may be such tools in the near future, that's why I think
exception-specifications should be left in the language until
such tools can check them.
I am working on such a tool that computes run-time information
doing only static analysis (you can have a look at
www.polyspace.com/cpp.htm, although it does not provide much
information on which operations exactly are checked in C++),
I guess some other people at other companies too.
For example, the tool I'm working on does find the 3 trivial errors
shown in a previous post (an integer overflow, an access to
uninitialized data and an exception not allowed by the
exception-specification).
As for exceptions, it does the following:
- for each function it tells you when:
- it throws exceptions for sure
- it does never throw exceptions
- it may throw or not (either because it actually will throw
in some cases and won't in others, or because the tool
cannot decide it)
- for each function with an exception-specification, it tells:
- if the exception-specification is violated by the exceptions
thrown for sure
- if the exception-specification is verified by the exceptions
thrown for sure
- if it may be violated or verified (again, either because
it is the case in the program, or because the tool cannot
decide it)
I agree with James Kanze when he says it is a matter of specifying
some expected behaviour, when the user feels like it is compulsory
to make his program run properly. This may be useful today when
testing, if a test aborts due to exception-specification violation,
it may be useful in the future when some tools can prove/disprove it.
Yannick
>Mary K. Kuhner wrote:
>> I don't want the fact that a low-level routine in my
>> directed graph rearrangement subsystem can throw
>> "too_many_migrations"
>> to have to be reflected in exception specs of every doggone
>> function all the way up to the catcher, eight levels above it.
>Couldn't you have an exception tree - all the exceptions you throw to
>be based on some class (like say dg_exception_base), then your throw
>spec would include the base class and the particular things your
>function threw.
In my hands, at least, this rapidly leads to functions being
declared to throw std::exception. At which point it is not
very useful to have exception specs at all.
I haven't yet found a case in which I wanted to know *what*
exceptions something throws, but several cases in which it
would have been good to know that it throws absolutely nothing.
For example, no matter what type something throws, if it throws
at all I can't use it unwrapped in a destructor.
[casting away an exception spec]
>Think of the fun you'd have if that went wrong though. If you said
>void func() throw()
>{
> Some_Rather_Complex_Class xclass; //Huge complex constructor &
>destructor
>//....code that couldn't throw an exception
> exception_cast<throw()> wibble();
>//... more code that doesn't throw exceptions
>}
>presumably the compiler will assume wibble() doesn't throw, won't put
>any code into func() to catch exceptions (after all, that's the
>optimisation you should make if all the functions you call are
>throw()), and if wibble does throw an exception, it'll pass straight
>into the caller of func, without calling the destructor of xclass.
>That could be even more fun if func was actually a destructor.
This is true. However, if I write this code (in a destructor) with
current C++ exception specs and it throws, it kills my program. And
if I write it without exception specs, it kills my program anyway.
(If this is not a dtor, maybe it just corrupts my program.) I'd
prefer having such dangers plainly marked by a red flag like
exception_cast rather than having them sit silently in the destructor....
We could always make a coding standard against exception_cast
so that everyone who used it had to justify it. It's hard to make
a coding standard "Don't call functions that can throw from a dtor"
when there is no automated way (that I know of) to check if a
function can throw.
It's not something I would expect to use very often. It's like
writing a log() function that has undefined behavior when passed
zero. I have one of these, because in some of our speed-critical
code (a) I know it won't be passed zero, and (b) I can't afford
the time to check for zero within log(). Telling the compiler
"trust me" is intrinsically risky, but sometimes you need to.
Current exception specs are "trust me, and shoot me dead if I
lied to you." I haven't found a use for that behavior yet at all.
Mary Kuhner mkku...@eskimo.com
> I haven't yet found a case in which I wanted to know *what*
> exceptions something throws, but several cases in which it
> would have been good to know that it throws absolutely nothing.
At first pass, I think it is essential to know can throw / cant throw.
A throw spec beyond that is, I think, useful documentation, but I agree
it needs a certain amount of control if it is not to dissolve into
having no exception spec because you have given up trying to work out
what you could throw.
> For example, no matter what type something throws, if it throws
> at all I can't use it unwrapped in a destructor.
Sad, but true.
You could make a coding standard that says you must always enclose
destructor code in a try / catch block. Not that I can see that being
popular, but it would be 100% safe. I don't think the language is
helping us very much here.
> It's not something I would expect to use very often. It's like
> writing a log() function that has undefined behavior when passed
> zero. I have one of these, because in some of our speed-critical
> code (a) I know it won't be passed zero, and (b) I can't afford
> the time to check for zero within log(). Telling the compiler
> "trust me" is intrinsically risky, but sometimes you need to.
>
> Current exception specs are "trust me, and shoot me dead if I
> lied to you." I haven't found a use for that behavior yet at all.
And I totally agree with that!