      ______________________________________________________________________

      15   Exception handling                                       [except]

      ______________________________________________________________________

    1 Exception handling provides a way of transferring control and informa-
      tion  from  a point in the execution of a program to an exception han-
      dler associated with a point previously passed by  the  execution.   A
      handler  will  be  invoked  only by a throw-expression invoked in code
      executed in the handler's try block or in functions  called  from  the
      handler's try block .
              try-block:
                       try compound-statement handler-seq
              function-try-block:
                       try  ctor-initializeropt function-body handler-seq
              handler-seq:
                      handler handler-seqopt
              handler:
                      catch ( exception-declaration ) compound-statement
              exception-declaration:
                      type-specifier-seq declarator
                      type-specifier-seq abstract-declarator
                      type-specifier-seq
                      ...
              throw-expression:
                      throw assignment-expressionopt
      A  try-block  is  a statement (_stmt.stmt_).  A throw-expression is of
      type void.  Code that executes a throw-expression is said to "throw an
      exception;" code that subsequently gets control is called a "handler."
      [Note: within this clause "try block" is taken to mean both  try-block
      and function-try-block.  ]

    2 A  goto,  break, return, or continue statement can be used to transfer
      control out of a try block or handler, but not into  one.   When  this
      happens,  each variable declared in the try block will be destroyed in
      the context that directly contains its declaration.  [Example:
              lab:  try {
                         T1 t1;
                         try {
                                T2 t2;
                                if (condition)
                                      goto lab;
                         } catch(...) { /* handler 2 */ }
                    } catch(...) { /*  handler 1 */ }
      Here, executing goto lab; will destroy first t2, then t1, assuming the
      condition  does  not  declare  a variable.  Any exception raised while
      destroying t2 will result in executing handler 2; any exception raised
      while destroying t1 will result in executing handler 1.  ]

    3 A  function-try-block  associates a handler-seq with the ctor-initial-
      izer, if present, and the function-body.  An exception  thrown  during
      the  execution  of the initializer expressions in the ctor-initializer
      or during the execution of the function-body transfers  control  to  a
      handler in a function-try-block in the same way as an exception thrown
      during the execution of a try-block transfers control  to  other  han-
      dlers.  [Example:
              int f(int);
              class C {
                      int i;
                      double d;
              public:
                      C(int, double);
              };
              C::C(int ii, double id)
              try
                      : i(f(ii)), d(id)
              {
                      // constructor function body
              }
              catch (...)
              {
                      // handles exceptions thrown from the ctor-initializer
                      // and from the constructor function body
              }
       --end example]

      15.1  Throwing an exception                             [except.throw]

    1 Throwing  an  exception  transfers control to a handler.  An object is
      passed and the type of that object determines which handlers can catch
      it.  [Example:
              throw "Help!";
      can be caught by a handler of some char* type:
              try {
                  // ...
              }
              catch(const char* p) {
                  // handle character string exceptions here
              }
      and
              class Overflow {
                  // ...
              public:
                  Overflow(char,double,double);
              };
              void f(double x)
              {
                  // ...
                  throw Overflow('+',x,3.45e107);
              }
      can be caught by a handler for exceptions of type Overflow

              try {
                  // ...
                  f(1.2);
                  // ...
              }
              catch(Overflow& oo) {
                  // handle exceptions of type Overflow here
              }
       --end example]

    2 When  an  exception  is  thrown, control is transferred to the nearest
      handler with a matching type (_except.handle_);  "nearest"  means  the
      handler  whose  try  block  was most recently entered by the thread of
      control and not yet exited.

    3 A throw-expression initializes a temporary object, the type  of  which
      is  determined by removing any top-level cv-qualifiers from the static
      type of the operand of throw and adjusting the type from "array of  T"
      or  "function  returning  T" to "pointer to T" or "pointer to function
      returning T", respectively. The temporary is used  to  initialize  the
      variable named in the matching handler (_except.handle_).  The type of
      the throw-expression shall not be an incomplete type, or a pointer  or
      reference  to  an  incomplete  type,  other  than  void*, const void*,
      volatile void*, or const volatile void*.  Except  for  these  restric-
      tions  and the restrictions on type matching mentioned in _except.han-
      dle_, the operand of throw is treated exactly as a  function  argument
      in a call (_expr.call_) or the operand of a return statement.

    4 The  memory  for  the  temporary copy of the exception being thrown is
      allocated   in   an   unspecified   way,   except    as    noted    in
      _basic.stc.dynamic.allocation_.   The  temporary  persists  as long as
      there is a handler being executed for that exception.  In  particular,
      if  a  handler exits by executing a throw; statement, that passes con-
      trol to another handler for  the  same  exception,  so  the  temporary
      remains.  If the use of the temporary object can be eliminated without
      changing the meaning of the program except for the execution  of  con-
      structors  and  destructors  associated  with the use of the temporary
      object (_class.temporary_), then the exception in the handler  can  be
      initialized  directly with the argument of the throw expression.  When
      the thrown object is a class object, and the copy constructor used  to
      initialize  the  temporary copy is not accessible, the program is ill-
      formed (even when the temporary object could otherwise be eliminated).
      Similarly,  if  the  destructor for that object is not accessible, the
      program is ill-formed (even when the temporary object could  otherwise
      be eliminated).

    5 A  throw-expression  with no operand rethrows the exception being han-
      dled without copying it.  [Example: code that must be executed because
      of  an  exception  yet  cannot  completely handle the exception can be
      written like this:

              try {
                  // ...
              }
              catch (...) {  // catch all exceptions

                  // respond (partially) to exception

                  throw;     // pass the exception to some
                             // other handler
              }
       --end example]

    6 The exception thrown is the one most recently caught and not finished.
      An  exception is considered caught when initialization is complete for
      the formal parameter of the corresponding catch clause, or when termi-
      nate()  or  unexpected()  is  entered due to a throw.  An exception is
      considered finished when the corresponding catch clause exits or  when
      unexpected() exits after being entered due to a throw.

    7 If  no exception is presently being handled, executing a throw-expres-
      sion with no operand calls terminate() (_except.terminate_).

      15.2  Constructors and destructors                       [except.ctor]

    1 As control passes from a throw-expression to  a  handler,  destructors
      are  invoked for all automatic objects constructed since the try block
      was entered.  The automatic objects are destroyed in the reverse order
      of the completion of their construction.

    2 An object that is partially constructed will have destructors executed
      only for its fully constructed sub-objects.  Should a constructor  for
      an  element  of  an  automatic array throw an exception, only the con-
      structed elements of that array will be destroyed.  If the  object  or
      array  was  allocated  in a new-expression and the new-expression does
      not   contain   a    new-placement,    the    deallocation    function
      (_basic.stc.dynamic.deallocation_, _class.free_) is called to free the
      storage occupied by the object; the deallocation function is chosen as
      specified  in  _expr.new_.   If the object or array was allocated in a
      new-expression and the new-expression contains  a  new-placement,  the
      storage  occupied  by the object is deallocated only if an appropriate
      placement operator delete is found, as specified in _expr.new_.

    3 The process of calling destructors for automatic  objects  constructed
      on  the  path  from a try block to a throw-expression is called "stack
      unwinding."

      15.3  Handling an exception                            [except.handle]

    1 The exception-declaration in a handler describes the type(s) of excep-
      tions that can cause that handler to be entered.  The exception-decla-
      ration shall not denote an incomplete type.  The exception-declaration
      shall  not  denote a pointer or reference to an incomplete type, other
      than void*, const void*, volatile  void*,  or  const  volatile  void*.
      Types shall not be defined in an exception-declaration.

    2 A  handler  of type "array of T" or "function returning T" is adjusted
      to be of type "pointer to T" or "pointer  to  function  returning  T",
      respectively.

    3 A  handler  is a match for a throw-expression with an object of type E
      if

      --The handler is of type cv T or cv T& and E and T are the  same  type
        (ignoring the top-level cv-qualifiers), or

      --the  handler is of type cv T or cv T& and T is an unambiguous public
        base class of E, or

      --the handler is of type cv1 T* cv2 and E is a pointer type  that  can
        be converted to the type of the handler by either or both of

        --a  standard  pointer conversion (_conv.ptr_) not involving conver-
          sions to pointers to private or protected or ambiguous classes

        --a qualification conversion

    4 [Example:
              class Matherr { /* ... */ virtual vf(); };
              class Overflow: public Matherr { /* ... */ };
              class Underflow: public Matherr { /* ... */ };
              class Zerodivide: public Matherr { /* ... */ };
              void f()
              {
                  try {
                      g();
                  }
                  catch (Overflow oo) {
                      // ...
                  }
                  catch (Matherr mm) {
                      // ...
                  }
              }
      Here, the Overflow handler will catch exceptions of type Overflow  and
      the  Matherr  handler will catch exceptions of type Matherr and of all
      types publicly derived  from  Matherr  including  exceptions  of  type
      Underflow and Zerodivide.  ]

    5 The  handlers  for a try block are tried in order of appearance.  That
      makes it possible to write handlers that can never  be  executed,  for
      example by placing a handler for a derived class after a handler for a
      corresponding base class.

    6 A ...  in a handler's exception-declaration functions similarly to ...
      in  a  function  parameter  declaration;  it specifies a match for any
      exception.  If present, a ...  handler shall be the last  handler  for
      its try block.

    7 If  no  match  is found among the handlers for a try block, the search
      for a matching handler continues  in  a  dynamically  surrounding  try
      block.

    8 An  exception  is  considered handled upon entry to a handler.  [Note:
      the stack will have been unwound at that point.  ]

    9 If no matching handler is found in a program, the function terminate()
      (_except.terminate_)  is  called.  Whether or not the stack is unwound
      before calling terminate() is implementation-defined.

    10Referring to any non-static member or base class of an object  in  the
      handler  for  a  function-try-block of a constructor or destructor for
      that object results in undefined behavior.

    11The fully constructed base classes and members of an object  shall  be
      destroyed  before  entering  the  handler of a function-try-block of a
      constructor or destructor for that object.

    12The scope and lifetime of the parameters of a function or  constructor
      extend into the handlers of a function-try-block.

    13Exceptions  thrown in destructors of objects with static storage dura-
      tion or in constructors of namespace-scope objects are not caught by a
      function-try-block on main().

    14If  the  handlers of a function-try-block contain a jump into the body
      of a constructor or destructor, the program is ill-formed.

    15If a return statement appears in a handler of  the  function-try-block
      of a constructor, the program is ill-formed.

    16The  exception being handled is rethrown if control reaches the end of
      a handler of the function-try-block of a  constructor  or  destructor.
      Otherwise,  a  function returns when control reaches the end of a han-
      dler for the function-try-block (_stmt.return_).

    17When the exception-declaration specifies a class  type,  a  copy  con-
      structor  is  used  to  initialize  either  the object declared in the
      exception-declaration or, if the exception-declaration does not  spec-
      ify  a  name,  a  temporary object of that type.  The object shall not
      have an abstract class type.  The object is destroyed when the handler
      exits,  after  the  destruction  of  any automatic objects initialized
      within the handler.  The copy  constructor  and  destructor  shall  be
      accessible in the context of the handler.  If the copy constructor and
      destructor are implicitly declared (_class.copy_), such a use  in  the
      handler  causes  these  functions to be implicitly defined; otherwise,
      the program shall provide a definition for these functions.

    18If the use of a temporary object can be  eliminated  without  changing
      the  meaning  of  the program except for execution of constructors and
      destructors associated with the use of the temporary object, then  the
      optional  name can be bound directly to the temporary object specified
      in a throw-expression causing the handler to be  executed.   The  copy

      constructor  and destructor associated with the object shall be acces-
      sible even when the temporary object is eliminated.

    19When the handler declares a non-constant object, any changes  to  that
      object  will  not  affect the temporary object that was initialized by
      execution of the throw-expression.  When the handler declares a refer-
      ence  to  a  non-constant object, any changes to the referenced object
      are changes to the temporary object initialized when the throw-expres-
      sion was executed and will have effect should that object be rethrown.

      15.4  Exception specifications                           [except.spec]

    1 A function  declaration  lists  exceptions  that  its  function  might
      directly  or indirectly throw by using an exception-specification as a
      suffix of its declarator.
              exception-specification:
                      throw ( type-id-listopt )
              type-id-list:
                      type-id
                      type-id-list ,  type-id
      An exception-specification shall appear only on a function  declarator
      in  a function, pointer, reference or pointer to member declaration or
      definition.  An exception-specification shall not appear in a  typedef
      declaration.  [Example:
              void f() throw(int);             // OK
              void (*fp)() throw (int);        // OK
              void g(void pfa() throw(int));   // OK
              typedef int (*pf)() throw(int);  // ill-formed
       --end example] A type denoted in an exception-specification shall not
      denote an incomplete type. A type denoted in  an  exception-specifica-
      tion  shall  not  denote a pointer or reference to an incomplete type,
      other than void*, const  void*,  volatile  void*,  or  const  volatile
      void*.

    2 If  any  declaration of a function has an exception-specification, all
      declarations, including the definition and an explicit specialization,
      of  that  function shall have an exception-specification with the same
      set of type-ids.  If any declaration of a pointer to function,  refer-
      ence to function, or pointer to member function has an exception-spec-
      ification, all occurrences of that declaration shall  have  an  excep-
      tion-specification  with  the  same  set  of type-ids.  In an explicit
      instantiation directive an exception-specification may  be  specified,
      but  is not required. If an exception-specification is specified in an
      explicit instantiation directive, it shall have the same set of  type-
      ids  as other declarations of that function.  A diagnostic is required
      only if the sets of type-ids are different within a single translation
      unit.

    3 If  a  virtual  function  has an exception-specification, all declara-
      tions, including the definition, of any function that  overrides  that
      virtual function in any derived class shall only allow exceptions that
      are allowed by the exception-specification of the base  class  virtual
      function.  [Example:

              struct B {
                  virtual void f() throw (int, double);
                  virtual void g();
              };

              struct D: B {
                  void f();                    // ill-formed
                  void g() throw (int);        // OK
              };
      The  declaration  of  D::f  is ill-formed because it allows all excep-
      tions, whereas B::f allows only int  and  double.   ]  Similarly,  any
      function  or  pointer  to  function  assigned  to,  or initializing, a
      pointer to function shall only allow exceptions that  are  allowed  by
      the pointer or function being assigned to or initialized.  [Example:
              void (*pf1)();    // no exception specification
              void (*pf2)() throw(A);

              void f()
              {
                      pf1 = pf2;  // ok: pf1 is less restrictive
                      pf2 = pf1;  // error: pf2 is more restrictive
              }
       --end example]

    4 In  such  an assignment or initialization, exception-specifications on
      return types and  parameter  types  shall  match  exactly.   In  other
      assignments  or  initializations, exception-specifications shall match
      exactly.

    5 Types shall not be defined in exception-specifications.

    6 An exception-specification can include the same type  more  than  once
      and  can  include classes that are related by inheritance, even though
      doing so is redundant.  An exception-specification  can  also  include
      the class std::bad_exception (_lib.bad.exception_).

    7 If  a class X is in the type-id-list of the exception-specification of
      a function, that function is said to allow exception objects of  class
      X  or any class publicly and unambiguously derived from X.  Similarly,
      if a pointer type Y* is in the type-id-list of the  exception-specifi-
      cation  of  a  function,  the function allows exceptions of type Y* or
      that are pointers to any type publicly and unambiguously derived  from
      Y.   Otherwise,  a  function only allows exceptions that have the same
      type as the types specified in the type-id-list of its exception-spec-
      ification.

    8 Whenever  an  exception  is  thrown  and  the  search  for  a  handler
      (_except.handle_) encounters the outermost block of a function with an
      exception-specification,   the   function   unexpected()   is   called
      (_except.unexpected_) if the exception-specification  does  not  allow
      the exception.  [Example:

              class X { };
              class Y { };
              class Z: public X { };
              class W { };

              void f() throw (X, Y)
              {
                  int n = 0;
                  if (n) throw X();        // OK
                  if (n) throw Z();        // also OK
                  throw W();               // will call unexpected()
              }
       --end example]

    9 The function unexpected() may throw an exception that will satisfy the
      exception-specification for which it was invoked, and in this case the
      search  for  another handler will continue at the call of the function
      with this exception-specification (see _except.unexpected_), or it may
      call terminate().

    10An  implementation  shall not reject an expression merely because when
      executed it throws or might throw an  exception  that  the  containing
      function does not allow.  [Example:
              extern void f() throw(X, Y);

              void g() throw(X)
              {
                      f();                 // OK
              }
      the  call  to  f is well-formed even though when called, f might throw
      exception Y that g does not allow.  ]

    11A function with no exception-specification allows all  exceptions.   A
      function  with  an  empty  exception-specification,  throw(), does not
      allow any exceptions.

    12An exception-specification is not  considered  part  of  a  function's
      type.

    13An  implicitly declared special member function (_special_) shall have
      an exception-specification.  If f is an  implicitly  declared  default
      constructor,  copy  constructor, destructor, or copy assignment opera-
      tor, its implicit exception-specification specifies the type-id  T  if
      and  only if T is allowed by the exception-specification of a function
      directly invoked by f's  implicitly  definition;  f  shall  allow  all
      exceptions  if any function it directly invokes allows all exceptions,
      and f shall allow no exceptions if every function it directly  invokes
      allows no exceptions.  [Example:

              struct A {
                  A();
                  A(const A&) throw();
                  ~A() throw(X);
              };
              struct B {
                  B() throw();
                  B(const B&) throw();
                  ~B() throw(Y);
              };
              struct D : public A, public B {
                  // Implicit declaration of D::D();
                  // Implicit declaration of D::D(const D&) throw();
                  // Implicit declaration of D::~D() throw (X,Y);
              };
      Furthermore,  if A::~A() or B::~B() were virtual, D::~D() would not be
      as restrictive as that of A::~A, and the program would  be  ill-formed
      since  a  function that overrides a virtual function from a base class
      shall have an exception-specification at least as restrictive as  that
      in the base class.  ]

      15.5  Special functions                               [except.special]

    1 The  exception handling mechanism relies on two functions, terminate()
      and unexpected(), for coping with errors related to the exception han-
      dling mechanism itself (_lib.support.exception_).

      15.5.1  The terminate() function                    [except.terminate]

    1 In  the  following situations exception handling must be abandoned for
      less subtle error handling techniques:

      --when the exception handling mechanism, after  completing  evaluation
        of  the  expression  to be thrown but before the exception is caught
        (_except.throw_), calls a user function that exits via  an  uncaught
        exception,1)

      --when  the  exception  handling mechanism cannot find a handler for a
        thrown exception (_except.handle_), or

      --when  the  destruction  of  an   object   during   stack   unwinding
        (_except.ctor_) exits using an exception, or

      --when  construction  or destruction of a non-local object with static
        storage duration exits using an exception (_basic.start.init_), or

      --when execution of a function registered with atexit exits  using  an
        exception (_lib.support.start.term_), or

      _________________________
      1)  For  example, if the object being thrown is of a class with a copy
      constructor, terminate() will be called if that copy constructor exits
      with an exception during a throw.

      --when  a  throw-expression  with  no  operand  attempts to rethrow an
        exception and no exception is being handled (_except.throw_), or

      --when unexpected throws an exception which is not allowed by the pre-
        viously  violated exception-specification, and std::bad_exception is
        not included in that exception-specification  (_except.unexpected_),
        or

      --when  the  implementation's  default  unexpected_handler  is  called
        (_lib.unexpected.handler_)

    2 In such cases,
              void terminate();
      is called (_lib.exception.terminate_).

      15.5.2  The unexpected() function                  [except.unexpected]

    1 If a function with an exception-specification throws an exception that
      is not listed in the exception-specification, the function
              void unexpected();
      is  called  (_lib.exception.unexpected_)  immediately after completing
      the stack unwinding for the former function

    2 The unexpected() function shall not return, but it can throw  (or  re-
      throw) an exception.  If it throws a new exception which is allowed by
      the exception specification which previously was  violated,  then  the
      search  for  another handler will continue at the call of the function
      whose exception specification was violated.  If it throws or  rethrows
      an  exception that the exception-specification does not allow then the
      following happens: if the exception-specification does not include the
      class  std::bad_exception (_lib.bad.exception_) then the function ter-
      minate() is called, otherwise the thrown exception is replaced  by  an
      implementation-defined  object  of the type std::bad_exception and the
      search for another handler will continue at the call of  the  function
      whose exception-specification was violated.

    3 Thus,  an  exception-specification  guarantees  that  only  the listed
      exceptions will be thrown.  If  the  exception-specification  includes
      the  type std::bad_exception then any exception not on the list may be
      replaced by std::bad_exception within the function unexpected().

      15.5.3  The uncaught_exception() function            [except.uncaught]

    1 See _lib.uncaught_.

      15.6  Exceptions and access                            [except.access]

    1 If the exception-declaration in a catch clause has class type, and the
      function  in which the catch clause occurs does not have access to the
      destructor of that class, the program is ill-formed.

    2 An object can be thrown if it can be copied and destroyed in the  con-
      text of the function in which the throw-expression occurs.