______________________________________________________________________

  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-initializer-opt 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.  Any excep­
  tion 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.

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

  restrictions on type matching mentioned in _except.handle_ and the use
  of a temporary object, 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 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.

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.

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 [Note: the process of calling destructors for automatic  objects  con­
  structed  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 a public base class of E, 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_)  not  involving
      conversions to pointers to private or protected base classes.

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

  [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.   [Note:
  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.

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

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

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

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

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

13The exception being handled shall be rethrown if control  reaches  the
  end  of  a  handler  of  the  function-try-block  of  a constructor or
  destructor. Otherwise, the function shall return when control  reaches
  the end of a handler for the function-try-block (_stmt.return_).

14
  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.  [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 have an exception-specification at least as
  restrictive as that in the base class.  [Example:
          struct B {
              virtual void f() throw (int, double);
              virtual void g();
          };

          struct D: B {
              void f();                    // ill-formed
              void g() throw (int);        // OK
          };
    --end  example]  The  declaration  of  D::f is ill-formed because it
  allows all exceptions, whereas B::f allows only int and double.  Simi­
  larly,  any function or pointer to function assigned to, or initializ­
  ing, 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.  [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
  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 identifiers that
  represent incomplete types.  An exception 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*.

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, calls a user
    function that exits via an uncaught exception,1)

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

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

  --when an attempt by the implementation to destroy  an  object  during
    stack unwinding exits using an exception.

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

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

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

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 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 terminate() 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.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 occurs.