______________________________________________________________________

  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
          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.  A throw-expression is sometimes referred to  as  a  throw-
  point.   Code  that  executes  a  throw-expression is said to throw an
  exception; code that subsequently gets control is called a handler.

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.  For 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.  Any excep­
  tion raised while destroying t2 will result in  executing  handler  2;
  any exception raised while destroying t1 will result in executing han­
  dler 1.

  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.  For 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
          try {
              // ...
              f(1.2);
              // ...
          }
          catch(Overflow& oo) {
              // handle exceptions of type Overflow here
          }

2 When an exception is thrown, control is  transferred  to  the  nearest
  handler with an appropriate type; nearest means the handler whose try-
  block was most recently entered by the thread of control and  not  yet
  exited; appropriate type is defined in _except.handle_.

3 The  operand  of  a  throw  shall  be of a type with no ambiguous base
  classes.  That is, it shall be possible to convert  the  value  thrown
  unambiguously to each of its base classes.1)

4 A throw-expression initializes a temporary object of the  static  type
  of  the  operand of throw, ignoring the top-level cv-qualifiers of the
  operand's type, and uses that temporary to  initialize  the  appropri­
  ately-typed  variable named in the handler.  If the static type of the
  expression thrown is a class or a pointer or  reference  to  a  class,
  there  shall be an unambiguous conversion from that class type to each
  _________________________
  1)  If  the  value thrown has no base classes or is not of class type,
  this condition is vacuously satisfied.

  of its accessible base classes.  Except for that restriction  and  for
  the restrictions on type matching mentioned in _except.handle_ and the
  use of a temporary variable, the operand of throw is  treated  exactly
  as  a  function  argument  in a call (_expr.call_) or the operand of a
  return statement.

5 The memory for the temporary copy of the  exception  being  thrown  is
  allocated in an implementation-defined way.  The temporary persists as
  long as there is a handler being executed for that exception.  In par­
  ticular,  if  a  handler  exits  by executing a throw; statement, that
  passes control to another handler for the same exception, so the  tem­
  porary  remains.  If the use of the temporary object can be eliminated
  without changing the meaning of the program except for  the  execution
  of  constructors and destructors associated with the use of the tempo­
  rary object (_class.temporary_), then the exception in the handler can
  be initialized directly with the argument of the throw expression.

6 A  throw-expression  with no operand rethrows the exception being han­
  dled without copying it.  For 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
          }

7 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.

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

  15.2  Constructors and destructors                       [except.ctor]

1 As  control  passes  from  a throw-point to a handler, destructors are
  invoked for all automatic objects constructed since the try-block  was
  entered.

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, the storage occupied by that
  object is sometimes deleted also (_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 executed.  The exception-
  declaration shall not denote an incomplete type.

2 A handler with type T, const T, T&, or const  T&  is  a  match  for  a
  throw-expression with an object of type E if

    [1]T and E are the same type, or

    [2]T  is  an  accessible  (_conv.ptr_)  base class of E at the throw
      point, or

    [3]T is a pointer type and E is a pointer type that can be converted
      to  T  by  a standard pointer conversion (_conv.ptr_) at the throw
      point.

  +-------                 BEGIN BOX 1                -------+
  The intent was and is to  require  no  run-time  access  or  ambiguity
  checking.

  Paragraph  3 of _except.throw_ says that we can't throw an object that
  would require the handler mechanism to do ambiguity checks.

  Point [2] above says, in particular, that an  object  with  a  private
  class  can  be  thrown  if  and only if the thrower has access to that
  base.  This implies no violation of access, because the thrower  could
  have thrown the private class directly.

  This  implies  that an exception can be caught by a private class (the
  access check, like the ambiguity check is done at  the  throw  point).
  This  does  not  require  a  run-time access check.  It does, however,
  require that a object of a class with a private base class  is  trans­
  mitted  to  the  catch  point together with an indication if it can be
  caught by its private base class.

  It has been suggested that this should be  simplified  by  prohibiting
  the  throw  of an object of a class with a private base class.  It has
  also been suggested that run-time access checks  should  be  required.
  In  the  absence  of a proposal for change, the text will be clarified
  along the lines in this box.
  +-------                  END BOX 1                 -------+

  For 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 all
  types publicly derived from Matherr including  Underflow  and  Zerodi­
  vide.

3 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.

4 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.

5 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.

6 An exception is considered handled upon entry to a handler.  The stack
  will have been unwound at that point.

7 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.

  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.

  +-------                 BEGIN BOX 2                -------+
  Should it be possible to use  more  general  types  than  type-ids  in
  exception-specifications?   In  the  absence of a proposal for change,
  this box will be removed.
  +-------                  END BOX 2                 -------+

          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 declaration or definition.  An exception-specification shall not
  appear in a typedef declaration.  For 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

2 If any declaration of a function has an  exception-specification,  all
  declarations, including the definition, of that function shall have an
  exception-specification with the same set of type-ids.  If  a  virtual
  function  has  an exception-specification, all declarations, including
  the definition, of any function that overrides that  virtual  function
  in any derived class shall have an exception-specification at least as
  restrictive as that in the base class.  For 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 func­
  tion or pointer to function assigned to, or initializing, a pointer to
  function shall have an exception-specification at least as restrictive
  as that of the pointer or function being assigned to  or  initialized.
  For 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
          }

3 In  such  an assignment or initialization, exception-specifications on
  return types and parameter types shall match exactly.

  +-------                 BEGIN BOX 3                -------+
  This is needlessly restrictive.  We can safely relax this  restriction
  if needed.
  +-------                  END BOX 3                 -------+

4 In  other  assignments  or  initializations,  exception-specifications
  shall match exactly.

  +-------                 BEGIN BOX 4                -------+
  This is needlessly restrictive.  We can safely relax this  restriction
  if needed.
  +-------                  END BOX 4                 -------+

5 Calling a function through a declaration whose exception-specification
  is less restrictive that that of the  function's  definition  is  ill-
  formed.  No diagnostic is required.

6 Types shall not be defined in exception-specifications.

7 An  exception-specification  can include the same class more than once
  and can include classes related by inheritance, even though  doing  so
  is  redundant.   An  exception-specification  can include classes with
  ambiguous base classes, even though throwing objects of  such  classes
  is   ill-formed  (_except.throw_).   An  exception  specification  can
  include identifiers that represent incomplete types.  An exception can
  also include the name of the predefined class Xunexpected.

  +-------                 BEGIN BOX 5                -------+
  The  name  Xunexpected is under discussion and will change.  The exact
  meaning of ``predefined'' and a possible standard  library  specifica­
  tion of class Xunexpected is also being defined.
  +-------                  END BOX 5                 -------+

8 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 derived from X.  Similarly, if a pointer type
  Y* is in the type-id-list of the exception-specification  of  a  func­
  tion,  the  function allows exceptions of type Y* or that are pointers
  to any type publicly derived from Y*.

9 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.  For 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()
          }

10The 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.

11An implementation shall not reject an expression merely  because  when
  executed  it  throws  or  might throw an exception that the containing
  function does not allow.  For 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.

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

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

  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 Occasionally, exception handling must be  abandoned  for  less  subtle
  error handling techniques.  For example,

  --when  a exception handling mechanism, after completing evaluation of
    the object to be thrown, calls a user function  that  exits  via  an
    uncaught exception,2)

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

  --when the exception handling mechanism finds the stack corrupted, or

  --when a destructor called during stack unwinding caused by an  excep­
    tion tries to exit using an exception.

  _________________________
  2)  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.

2 In such cases,
          void terminate();
  is  called;  terminate()  calls  the function given on the most recent
  call of set_terminate()(_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;  unexpected()  calls the function given on the most recent
  call of set_unexpected()(_lib.exception.unexpected_).

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  an  exception  which  is  not allowed by the exception-
  specification  then  the  following   happens:   if   the   exception-
  specification  does  not  include the name of the predefined exception
  Xunexpected then the function terminate()  is  called,  otherwise  the
  thrown  exception  is  replaced by an implementation-defined object of
  the type Xunexpected and the search for another handler will  continue
  at  the  call  of  the function whose exception-specification was vio­
  lated.

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

  15.6  Exceptions and access                            [except.access]

1 The  parameter  of  a  catch  clause  obeys the same access rules as a
  parameter of the function in which the catch clause occurs.

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