______________________________________________________________________

  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.  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."
  [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-
  initializer,  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 handlers.  [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  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 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.  Except  for  the  restric­
  tions  on  type matching mentioned in _except.handle_ and the use of a
  temporary object, the operand of throw is treated exactly as  a  func­
  tion  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 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.
  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 elim­
  inated).  Similarly, if the destructor for that object is not accessi­
  ble, 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.

7 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.   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.deallcoation_, _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-
  declaration  shall  not denote an incomplete type.  Types shall not be
  defined in an exception-declaration.

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

  --T and E are the same type (ignoring the top-level cv-qualifiers), or

  --T is an unambiguous public base class of E, or

  --T is a pointer type and E is a pointer type that can be converted to
    T  by  a standard pointer conversion (_conv.ptr_) not involving con­
    versions to pointers to  private  or  protected  or  ambiguous  base
    classes,  or a qualification conversion (_conv.qual_), or a combina­
    tion of these two.

  +-------                 BEGIN BOX 1                -------+
  This implicitly bans handlers of volatile-qualified type.  There is no
  obvious  reason for the restriction, but no one has proposed to remove
  it.
  +-------                  END BOX 1                 -------+

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

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

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

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

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

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

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

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

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

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

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

14The  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_).

15When the catch handler specifies a class object, a copy constructor is
  used to initialize a temporary object which is bound to the optionally
  specified name in the exception-declaration  for  the  catch  handler.
  The  object  shall  not  have an abstract class type, since objects of
  those types shall not be created.  That object is destroyed  when  the
  handler is exited, after the destruction of any automatic objects ini­
  tialized within the handler.   The  copy  constructor  and  destructor
  shall  be accessible in the context of the catch handler.  If the copy
  constructor and destructor  are  implicitly  declared  (_class.copy_),
  such  a  use in the catch handler causes these functions to be implic­
  itly defined; otherwise, the program shall provide  a  definition  for
  these  functions.   If 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
  (or original) object specified in a throw-expression causing the catch
  handler to be executed.  The copy constructor and  destructor  associ­
  ated  with  the  object  shall  be  accessible even when the temporary
  object is eliminated.

16When the catch handler specifies a non-constant object, any changes to
  that  object  which  are effected while the handler has not exited are
  changes to the temporary copy for the handler and will not affect  the
  temporary  (or  original)  object that was initialized by execution of
  the throw-expression.  When the catch handler specifies a reference to
  a  non-constant  object,  any  changes  to  the  referenced object are
  changes to the temporary (or original)  object  initialized  when  the
  throw  expression 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.

  +-------                 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  function  or  pointer 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]

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

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
  allows  other  exceptions  than  those  allowed  by   the   exception-
  specification of the function's definition is ill-formed.  No diagnos­
  tic 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 identifiers that
  represent  incomplete  types.   An  exception-specification  can  also
  include the name of the predefined class bad_exception.

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 and unambiguously derived from X.   Similarly,
  if  a  pointer  type  Y*  is  in  the  type-id-list  of the exception-
  specification 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-
  specification.

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

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.  [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 In the following situations exception handling must be  abandoned  for
  less subtle error handling techniques:

  --when  a exception handling mechanism, after completing evaluation of
    the object to be thrown but before completing the initialization  of
    the  exception-declaration  in  the matching handler,1) calls a user
    function that exits via an uncaught exception,2)

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

  --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 bad_exception  is  not
    included in that exception-specification (_except.unexpected_), or

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

  --when the implementation's exception  handling  mechanism  encounters
    some internal error.

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

  _________________________
  1) i.e., when uncaught_exception() (_except.uncaught_) returns true.
  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 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
  name  of the predefined exception bad_exception then the function ter­
  minate() is called, otherwise the thrown exception is replaced  by  an
  implementation-defined object of the type 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  name  bad_exception  then  any  exception  not on the list may be
  replaced by bad_exception within the function unexpected().

  15.5.3  The uncaught_exception() function            [except.uncaught]

1 The predicate
          bool uncaught_exception();
  returns true after completing evaluation of the object  to  be  thrown
  until  completing  the  initialization of the exception-declaration in
  the matching handler (_lib.uncaught_). This includes  stack  unwinding
  (_except.ctor_).

  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.