______________________________________________________________________

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

  15.1  Throwing an exception                             [except.throw]

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

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

2 When an exception is thrown, control is  transferred  to  the  nearest
  handler  with  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.  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.  The temporary persists as long as
  there is a handler being executed for that exception.  In  particular,
  if  a  handler exits by executing a throw; statement, that passes con­
  trol to another handler for  the  same  exception,  so  the  temporary
  remains.  If the use of the temporary object can be eliminated without
  changing the meaning of the program except for the execution  of  con­
  structors  and  destructors  associated  with the use of the temporary
  object (_class.temporary_), then the exception in the handler  can  be
  initialized  directly with the argument of the throw expression.  When
  the thrown object is a class object, and the copy constructor used  to
  initialize  the  temporary copy is not accessible, the program is ill-
  formed (even when the temporary object could otherwise be eliminated).
  Similarly,  if  the  destructor for that object is not accessible, the
  program is ill-formed (even when the temporary object could  otherwise
  be eliminated).

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

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

              // respond (partially) to exception

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

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

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

  15.2  Constructors and destructors                       [except.ctor]

1 As  control  passes  from  a throw-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.deallocation_, _class.free_) is called to free the
  storage occupied by the object; the deallocation function is chosen as
  specified in _expr.new_.  If the object or array was  allocated  in  a
  new-expression  and  the  new-expression contains a new-placement, the
  storage occupied by the object is deallocated only if  an  appropriate
  placement operator delete is found, as specified in _expr.new_.

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

  15.3  Handling an exception                            [except.handle]

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

2 A handler 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 a standard  pointer  con­
    version  (_conv.ptr_)  not involving conversions to pointers to pri­
    vate or protected or ambiguous classes, or  a  qualification-conver­
    sion (_conv.qual_), or a combination of these two.

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.

12Exceptions 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().

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

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

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

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

17When 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 1                     -------+
  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 1                      -------+

          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] A type denoted in an exception-specification shall not
  denote an incomplete type. A type denoted in  an  exception-specifica­
  tion  shall  not  denote a pointer or reference to an incomplete type,
  other than void*, const  void*,  volatile  void*,  or  const  volatile
  void*.

2 If  any  declaration of a function has an exception-specification, all
  declarations, including the definition and an explicit specialization,
  of  that  function shall have an exception-specification with the same
  set of type-ids.  If any declaration of a pointer to function  has  an
  exception-specification,  all  declarations of that pointer shall have
  an exception-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 spec­
  ified  in  an explicit instantiation directive, it shall have the same
  set of type-ids as other declarations of that function.  A  diagnostic
  is required only if the sets of type-ids are different within a single
  translation unit.

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

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

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

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

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

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

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

  +-------                      BEGIN BOX 3                     -------+
  This  is needlessly restrictive.  We can safely relax this restriction
  if needed.
  +-------                       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 include identi­
  fiers 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.

14An implicitly declared special member function (_special_) shall  have
  an  exception-specification.   If  f is an implicitly declared default
  constructor, copy constructor, destructor, or copy  assignment  opera­
  tor,  its  implicit exception-specification specifies the type-id T if

  and only if T is allowed by the exception-specification of a  function
  directly  invoked  by  f's  implicitly  definition;  f shall allow all
  exceptions if any function it directly invokes allows all  exceptions,
  and  f shall allow no exceptions if every function it directly invokes
  allows no exceptions.  [Example:
          struct A {
              A();
              A(const A&) throw();
              ~A() throw(X);
          };
          struct B {
              B() throw();
              B(const B&) throw();
              ~B() throw(Y);
          };
          struct D : public A, public B {
              // Implicit declaration of D::D();
              // Implicit declaration of D::D(const D&) throw();
              // Implicit declaration of D::~D() throw (X,Y);
          };
  Furthermore, if A::~A() or B::~B() were virtual, D::~D() would not  be
  as  restrictive  as that of A::~A, and the program would be ill-formed
  since a function that overrides a virtual function from a  base  class
  shall  have an exception-specification at least as restrictive as that
  in the base class.  ]

  15.5  Special functions                               [except.special]

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

  15.5.1  The terminate() function                    [except.terminate]

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

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

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

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

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

  15.5.2  The unexpected() function                  [except.unexpected]

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

2 The unexpected() function shall not return, but it can throw  (or  re-
  throw) an exception.  If it throws a new exception which is allowed by
  the exception specification which previously was  violated,  then  the
  search  for  another handler will continue at the call of the function
  whose exception specification was violated.  If it throws or  rethrows
  an  exception that the exception-specification does not allow then the
  following happens: if the exception-specification does not include the
  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 See _lib.uncaught_.

  15.6  Exceptions and access                            [except.access]

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

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