______________________________________________________________________

  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 (clause _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 const 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  for  which  the compound-statement ctor-initializer, or func-
  tion-body following the try keyword 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.  [Note: the temporary object created for a
  throw-expression that is a string literal is never of  type  char*  or
  wchar_t*;  that  is,  the special conversions for string literals from
  the types "array of const char" and "array of const  wchar_t"  to  the
  types  "pointer  to  char"  and  "pointer  to  wchar_t",  respectively
  (_conv.array_), are never applied to a I. throw-expression  .   ]  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  restrictions and the restrictions on type
  matching mentioned in _except.handle_, 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.  When the last handler being executed for the exception exits
  by  any  means other than throw; the temporary object is destroyed and
  the implementation may deallocate the memory for the temporary object;
  any  such deallocation is done in an unspecified way.  The destruction
  occurs immediately after the destruction of the object declared in the
  exception-declaration in the handler.

5 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 temporary object
  (_class.temporary_), then the exception in the handler can be initial-
  ized  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).

6 A  throw-expression  with no operand rethrows the exception being han-
  dled.  The exception is reactivated with the  existing  temporary;  no
  new temporary exception object is created.  The exception is no longer
  considered to be caught; therefore, the value of  uncaught_exception()
  will  again  be true.  [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]

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 or when
  unexpected() exits after being entered due to a throw.

8 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 or  partially  destroyed  will
  have destructors executed for all of its fully constructed subobjects,
  that is, for subobjects for which the constructor has completed execu-
  tion  and  the  destructor has not yet begun execution.  Should a con-
  structor for an element of an automatic array throw an exception, only
  the  constructed  elements  of  that  array will be destroyed.  If the
  object or array was allocated in a new-expression and the  new-expres-
  sion  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."   [Note:  If  a  destructor  called during stack unwinding
  exits with an exception, terminate is called (_except.terminate_).  So
  destructors  should generally catch exceptions and not let them propa-
  gate out of the destructor.   --end note]

  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
    [Note: a throw-expression which is an integral  constant  expression
    of  integer  type that evaluates to zero does not match a handler of
    pointer  type;  that  is,  the  null  pointer  constant  conversions
    (_conv.ptr_, _conv.mem_) do not apply.  ]

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 this call to 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_).  Flowing off the end
  of a function-try-block is equivalent to a return with no value;  this
  results   in   undefined   behavior   in  a  value-returning  function
  (_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.

  +-------                      BEGIN BOX 1                     -------+
  The option of aliasing the handler variable with the temporary  object
  is  almost  certainly  wrong,  and needs to be changed (given a ballot
  comment) in the next version.
  +-------                       END BOX 1                      -------+

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

  +-------                      BEGIN BOX 2                     -------+
  Shouldn't the copy constructor be accessible for any (top-level) class
  type, so that it is possible to transform the exception  specification
  into a function try block?
  +-------                       END BOX 2                      -------+

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:

  class A { /* ... */ };
  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.

  +-------                      BEGIN BOX 3                     -------+
  This was commented out in the typesetting document source.  Why?

5 Calling a function through a declaration whose exception-specification
  allows other exceptions than those allowed by the exception-specifica-
  tion of the function's definition is  ill-formed.   No  diagnostic  is
  required.  [San Diego motion 23]
  +-------                       END BOX 3                      -------+

6 Types shall not be defined in exception-specifications.

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

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

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.

14An implicitly declared  special  member  function  (clause  _special_)
  shall have an exception-specification.  If f is an implicitly declared
  default constructor, copy constructor, destructor, or copy  assignment
  operator, its implicit exception-specification specifies the type-id T
  if and only if T is allowed by the exception-specification of a  func-
  tion  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_).  [Note: in the situation where
  no matching handler is found, it is implementation-defined whether  or
  not  the  stack is unwound before terminate() is called.  In all other
  situations, the stack shall  not  be  unwound  before  terminate()  is
  called.  ]

  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 The function
  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.
  If the exception is  rethrown  (_except.throw_),  uncaught_exception()
  returns true from the point of rethrow until the rethrown exception is

  caught again.

  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.