uC++ EHM

Exception List

An exception list is part of a routine’s prototype specifying which exception types may propagate out of the routine to its caller.

Why constrain which exceptions a routine can raise?

So callers (and the compiler) know what to expect. A missing handler for an unexpected exception-type is exactly what caused the Ariane 5 rocket to self-destruct — arithmetic overflow in control software, no handler, $370 million loss. Exception lists catch that at compile time (checked types) or at runtime (special failure exception / program termination).

Syntax

int g() throw(E) { ... throw E(); }   // "may throw E, nothing else"

Two kinds of checking

  • Checked/unchecked exception-type — Java, inheritance-based, static check.
  • Checked/unchecked routines — C++, list-based, dynamic check (deprecated in C++11, replaced with noexcept).

Why it hurts reuse

Checked exceptions are useful for engineering rigor but preclude reuse. Consider:

template <class T> void sort( T items[] ) throw( ?, ?, ... ) {
    // uses bool operator<( const T&, const T& );
}

You can’t know every exception type that < might propagate for every T — so any fixed exception-list excludes some legal types T.

Exception lists and polymorphism break down

// Left example: argument g has signature less restrictive than parameter p
void f( void (*p)() noexcept ) { p(); }
void g() noexcept(false) { throw E(); }
void h() {
    try { ... f( g ); ... } catch( E ) {}   // precluded — g's signature is wider than p's
}
 
// Right example: D::g overrides B::g with a wider signature
struct B { virtual void g() noexcept {} };
struct D : public B {
    void g() noexcept(false) { throw E(); }   // precluded — D::g wider than B::g
};

Both are rejected because a callable site that promised “no exceptions” can’t accept a callable that might throw.

Concurrent exceptions

Determining an exception list for a routine can become impossible for concurrent exceptions because they can propagate at any time — see Nonlocal Exception.