### Using try and catch

Many functions throw exceptions when they encounter unusual situations. To ensure that your code is robust, you should call such functions from within a try-block and then either handle or rethrow any resulting exceptions from within a catch-statement.

Because all exceptions are derived from the IException class, a single catch statement can catch any exception that might be thrown. The following example illustrates how you can do this:

    catch(IException &ie){
         // ...
         // code for all exception class exceptions
    }

On the other hand, if you wanted to deal with each kind of exception separately, you could have catch statements that looked like this:

    catch(IAccessError &ia){
         // ...
         // code for IAccessError exceptions
    }
    catch(IAssertionFailure &iaf){
         // ...
         // code for IAssertionFailure exceptions
    }
    // ...

The following example illustrates how you can safely call a function that might throw an exception. This sample code calls the new operator to create a huge array of integer pointers. The new operator throws an IOutOfMemory exception when there is insufficient memory available to satisfy a request for memory.

In the following code, a single invocation of the new operator exhausts all of the memory that is available for allocation. The catch statement specifies the base class IException rather than IOutOfMemory. If you know that a member function may throw an exception, but you do not know its exact type, you can specify a catch statement like this one to catch any possible exception.

    //   The new operator throwing an exception

    #include <iostream.h>
    #include <iexcept.hpp>
    #include <istring.hpp>

    #define TOOBIG 1000000000

    void main() {
       int i;
       try {
          int* istr = new int[TOOBIG];
       }
       catch(IException &ie)
       {
          cout << "Type of exception is: " << ie.name() << endl;
          cout << "Location of exception is: "
               << ie.locationAtIndex(0)->fileName() << endl;
          if (ie.isRecoverable())
             cout << "Exception is recoverable" << endl;
          else
             cout << "Exception is unrecoverable" << endl;
       }
    }

    Assuming that the constant TOOBIG is large enough to exhaust all of the memory available for
    allocation, this code produces the following output:

    Type of exception is: IOutOfMemory
    Location of exception is: ibase.C
    Exception is unrecoverable

The following is another example illustrating how you can safely call a function that might throw an exception. If you use the subscript operator on an IString object that is declared const, the operator will throw an IInvalidRequest exception if the index is out of the bounds of the IString object.

In the following code, an IString object is declared const, and then the subscript operator is used with an index beyond the size of the object.

    // Example that causes a subscript out of bounds exception

    #include <iostream.h>
    #include <iexcept.hpp>
    #include <istring.hpp>

    void main() {
       try {
          const IString ConstStr = "OFF";
          cout << ConstStr[4] << endl;
       }
       catch(IException &ie)
       {
          cout << "Type of exception is: " << ie.name() << endl;
          cout << "Location of exception is: "
               << ie.locationAtIndex(0)->fileName() << endl;
          if (ie.isRecoverable())
             cout << "Exception is recoverable" << endl;
          else
             cout << "Exception is unrecoverable" << endl;
       }
    }

Because the index is beyond the size of the `IString` object, the subscript operator throws an exception. When this code is run, the following output is produced:

    Type of exception is: IInvalidRequest
    Location of exception is: istring5.C
    Exception is recoverable

Using Throw Macros
Interpreting Exceptions
Using Assertion Macros
Rethrowing Exceptions
Deriving Your Own Exceptions
Tracing Exceptions

The Exceptions Mechanism
Using Exceptions