HPlogo HP C++ Version A.12.10 Release Notes: HP 9000 Computers > Chapter 3 Related Documentation

Information on Exception Handling Features

» 

Technical documentation

Complete book in PDF

 » Table of Contents

 » Index

Below is some valuable information on exception handling features published in previous release notes.

Exception handling is supported in both compiler mode and translator mode, and such object files can be intermixed. Use the +eh option to enable exception handling for both compiling and linking. There is some performance degradation when using the +eh option in translator mode.

Detecting Link Incompatibilities when Using Exception Handling

This release of HP C++ supports exception handling when the +eh option is specified. Note that code compiled with +eh is not link compatible with code that has not been compiled with +eh. There are three reasons for this:

  1. When +eh is enabled, constructors no longer allocate memory for heap objects; such memory is allocated before the constructor is called. For example, if non +eh code calls a +eh constructor to construct a heap object, memory for the heap object is not allocated.

  2. When +eh is enabled, all constructors perform a certain amount of bookkeeping to indicate how far object construction has progressed; this is needed because in the event of an exception, partially constructed objects need to be cleaned up. If +eh code calls a non +eh constructor, this bookkeeping does not take place; thus, in the event of an exception, there is incorrect information about the state of objects in procedures which called non +eh constructors.

  3. All +eh procedures perform a certain amount of bookkeeping to save information about the list of objects constructed within each procedure. Since non +eh procedures do not perform this bookkeeping, such procedures do not undergo any object cleanups in the event of an exception.

Detecting Link Incompatibilities in Shared Libraries

When the CC driver is used to produce a shared library (using -b), link incompatibilities are detected by c++patch using the same rules described above. When performing a link which involves shared libraries, HP C++ waits until run time to establish that each shared library linked in or explicitly loaded is compatible with the main executable. If any incompatibilities are detected, the default behavior is to print a warning message to stderr. If this default behavior is unacceptable, you can override it by linking in your own version of the routine __link_incompatibility.

For example, if you do not wish to have any warning of this kind at all, the following routine can be linked in:

extern "C" void __link_incompatibility
(const char* libname, int lib_mode) {
//libname is the name of the library
//lib_mode == 0 for a non +eh library
//lib_mode == 1 for a +eh library

//You can provide your own version to override the
//default behavior
//This is an empty body which does nothing
}

Exception Handling Language Clarifications

This section lists various exception handling language issues which should be considered clarifications of The Annotated C++ Reference Manual. These clarifications represent the behavior of HP's implementation of exception handling.

Issues in this section are organized as follows:

  • Throwing an Exception

  • Handling an Exception

  • Throw Specifications

  • terminate() and unexpected()

  • Other Issues

Throwing an Exception

  1. Can a class with an ambiguous base class be thrown? That is, should the following be legal?

    struct A { ... };
    struct B1 : A { ... };
    struct B2 : A { ... };
    struct C : B1, B2 { ... };
    void f()
    {
    C c;
    throw c; // legal?
    }

    No, throwing a class with an ambiguous base class is not legal.

  2. Can a class with multiple instances of the same base class be thrown if only one of the base class instances is accessible?

    No, a class with multiple instances of the same base class cannot be thrown even if only one of the base class instances is accessible.

  3. What happens when a reference is thrown?

    A temporary is allocated, the object referenced by the throw argument is copied into the temp, and the search for the appropriate handler is begun.

    When the handler is found, if its argument is not a reference type, the local is initialized from the temp. If the handler's local variable is of a reference type, the reference is made to refer to the temp.

    The possibly surprising effect of this is that if a reference to a global is thrown, and the handler's local is a reference type, the handler gets a reference to the temporary, not a reference to the global.

  4. Can the name of an overloaded function be thrown?

    No, the name of an overloaded function (really, its address) cannot be thrown.

  5. What is the precedence of throw?

    A throw-expression is an assignment-expression.

  6. Can a throw appear in a conditional expression? For example, is the following legal?

    void f()
    {
    int x;
    x ? throw : 12;
    }

    void g()
    {
    int x;
    x ? 12 : throw;
    }

    Yes, a throw can appear in a conditional expression.

  7. Are nested throws allowed?

    Yes. When a nested throw occurs, processing of the previous exception is abandoned and the new exception is processed.

  8. What happens if a rethrow occurs outside the dynamic context of a handler?

    The behavior of a rethrow outside the dynamic context of a handler is undefined.

  9. What happens if an exception is thrown in a signal handler?

    Throwing an exception in a signal handler is not supported. There is no way to predict when a signal handler will execute, consequently the signal handler could be called when the exception handling structures are in an inconsistent state.

  10. What happens if a longjmp is issued in a signal handler?

    This is not recommended for the same reason that throwing an exception in a signal handler is not supported. The signal handler interrupts processing of the code resulting in undefined data structures with unpredictable results.

Handling an Exception

  1. Should the implementation warn or generate a hard error for the appearance of a masked catch clause?

    The appearance of a masked catch clause is an error.

  2. Does the presence of a linkage specification affect the handlers that can catch (the address of) a function?

    No, the type of a function is not affected by a linkage specification.

    For example, this throw:

    extern "C" {
    void f(int);
    };

    void g()
    {
    throw f;
    }

    is catchable by:

    catch (void (*)())
  3. Can an incomplete type appear in a catch clause?

    No, an incomplete type cannot appear in a catch clause.

  4. When is an exception considered handled?

    An exception is considered handled when one of the following occurs:

    • a handler for the exception is invoked

    • terminate is invoked

    • unexpected is invoked

Throw Specifications

  1. Must all throw specifications on the definition and declarations for a given function agree?

    Yes, all throw specifications on the definition and declarations for a given function must agree.

  2. Can a class with ambiguous base classes be on a specification list? That is, is the following throw specification on bar legal?

    struct A { ... };
    struct B1 : A { ... };
    struct B2 : A { ... };
    struct C : B1, B2 { ... };

    void foo (C* cp)
    {
    w *cp; //error according to ANSI
    }

    void bar () throw(C); // legal?

    No, a class with an ambiguous base class cannot appear in a throw specification.

  3. Can a derived class of a class on a throw specification list also appear in that same throw specification list?

    Yes, a derived class of a class on a throw specification list can also appear in that same throw specification list.

  4. Can a function that lists a pointer to a base class in its throw specification list also throw a pointer to a derived class of that class?

    Yes, a function that lists a pointer to a base class in its throw specification list can throw a pointer to a derived class of that class.

  5. Can a reference appear in a throw specification list?

    Yes, a reference can appear in a throw specification list.

  6. Can a type appear more than once in a throw specification list?

    That is, is the following declaration legal?

    void baz() throw(A,A,A);     // legal?

    Yes, duplicate types are allowed in throw specification type lists.

  7. Can an incomplete type appear in a throw specification list? For example, should the following be legal?

    struct A;
    void f() throw(A) { }

    Yes, an incomplete type can appear in a throw specification list.

  8. Where can a throw specification appear?

    A throw specification can appear only in a function declaration or a function definition and only for the function being declared or defined. In particular, it can not appear within an argument list nor in a typedef.

terminate() and unexpected()

  1. What should be done when a thrown exception is not handled?

    No cleanups should take place; terminate should be called.

    If an unhandled exception occurs while constructing static objects, call terminate. If terminate then calls exit, any fully constructed or partially constructed statics should be destroyed.

    If an unhandled exception occurs while destroying static objects, call terminate. If terminate then calls exit, try to destroy any remaining static objects. Do not try again to destroy the object that caused the exception.

  2. Can terminate() call exit()?

    Yes, terminate() can call exit().

  3. Can unexpected() return?

    No, unexpected() cannot return.

  4. Can unexpected() throw or rethrow?

    Yes, unexpected() can throw or rethrow.

  5. What does unexpected() rethrow?

    A rethrow in unexpected() rethrows the exception that caused unexpected() to be called.

Other Issues

  1. Are transfers of control into try blocks and handlers legal?

    No, transfers of control into try blocks and handlers are not legal.

  2. Is it correct to consider an object constructed when its last statement is reached, while a destructor is considered complete just before its first statement is reached?

    An object is not considered fully constructed until everything in the constructor is finished. An object is considered partially destroyed before anything happens in the destructor.

  3. Should the EH run-time delete memory allocated by a new-with-placement?

    No, the EH run-time should not delete memory allocated by a new-with-placement.

  4. Should locals and globals be cleaned up when an unhandleable exception is thrown?

    No, locals and globals are not to be cleaned up when an unhandleable exception is thrown.

  5. Should an object for which a destructor has been called still be cleaned up by the EH run-time?

    A destructor should not be called explicitly on an object for which a destructor is called implicitly. Thus the EH run-time should not have to worry about whether an explicit destructor call has been issued for an object.

  6. Should exit() throw a standard exception to ensure that automatics are cleaned up?

    No, exit() should not throw an exception.

  7. What should happen when an exception is thrown from a function registered with atexit()?

    When an exception is thrown from a function registered with atexit(), terminate() should be called.

  8. What should happen if the user program calls alloca()?

    You can only use alloca() in translator mode. However, it is recommended that you avoid this function.

© 1998 Hewlett-Packard Development Company, L.P.