Boost logo

Boost :

From: Dave Abrahams (abrahams_at_[hidden])
Date: 2000-03-20 23:02:14


on 3/20/00 10:50 AM, Stephen Cleary at scleary_at_[hidden] wrote:

> The only benefit I can think of is a compiler that is working on a part
> of code in a try block -- if it can determine that that code cannot
> throw an exception, then the try/catches there can be removed. There
> are *many* problems, though:

Steve, I'm afraid you have the wrong picture here:

> 1) throw() will not guarantee that a function will not throw an
> exception -- it just guarantees that a different course of action will
> be taken. Because of this, throw() can only be used as a hint to the
> compiler that the function *should* not throw an exception.

Actually, no. The compiler knows that no exception other than those
specified (in this case no exceptions) may propagate out of the function. It
can use that information to remove try/catch blocks, but also exception
tables and destructor calls in the exception code path.

The problem is that few compilers implement this optimization, and any
conforming compiler must implement the moral equivalent of a try/catch block
to be sure that exceptions which don't match the specification get routed to
the unexpected handler. This has its own associated overheads. On most
compilers the result is a bigger (and sometimes slower) executable. To get
any benefit at all on other compilers, really consistent and careful
application of throw() specifications is required. If you just apply it at
some middle layers of the program without going all the way to leaf
functions, you again have an anti-optimization.

> 2) In order for throw() to be properly used as a hint, proper
> programming practice is required (i.e., only throw exceptions listed in
> the throw-spec), or else the compiler is just wasting its time.

No, you really can't throw anything else out of the function. Everything
else gets routed into the unexpected() handler.

> 3) On platforms that support faults as exceptions (meaning division
> by zero, access violation/seg fault, etc.) it is often difficult or
> impossible to predict whether exceptions of this type will be
> (implicitly) thrown by any given piece of code.

Faults are all undefined behavior, so you're basically not allowed to cause
them. If they are somehow mapped to exceptions that don't match a function's
exception-specification, execution should end up in the unexpected handler,
just as for any other exception, though actual mileage is of course up to
the platform to decide.

> 4) The code that the compiler is working on is presumably part of a
> try block; good programming practices will say that the only time to
> have a try/catch block is in the case where a) it is possible to get an
> exception, and b) we can recover from that exception. In other words,
> with a good programmer, this optimization would be useless (IMO).

Not really. Just for a simple example, the language standard requires a
compiler to generate exception tables to deal with the case where the
destructor of an auto variable throws an exception, unless the compiler can
prove that it won't happen. Using an empty exception-specification can, in
theory, help the compiler to do so.
 
> As is well-known, compilers can provide correct code just by wrapping
> each call to a function-with-exception-spec inside a try/catch.
> Furthermore, the except-spec *requires* these compilers to either
> provide the implicit try/catch or do something like the above.
>
> Based on the complexity of implementing such an optimization, and (by
> (4)) the probable uselessness of it, I don't think we will see it
> anytime soon.

Well, it already exists in the Sun and IBM compilers, and I expect to see it
in GCC in the near future.

> I believe that proper documentation will *always* include exception
> specifications, but that proper code never will [1].
>
> OTOH, I do see a possible usage for except-spec; namely, when debugging
> your code. I've never used it in this way, and its usefulness would be
> determined by platform specifics; but it might be helpful in finding
> unexpected (!) exceptions.
>
> Just my $0.02 :)
>
> -Steve
>
> [1] No, not even operator T*() { return ptr; }. Consider contrived
> example:
> int * tmp = (shared_ptr<int> *)(0)->operator int *(); // may throw
> access violation/seg fault

Might take your dog for a walk and make you a nice hot steaming cup of
latte, but don't count on it ;)

> Now, of *course* no programmer would write such code, but the compiler
> cannot predict that "this" *isn't* some invalid value, so it must err
> on the side of caution.

The-compiler-is-allowed-to-assume-you're-not-being-a-doofus'ly yr's,
Dave


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk