Exception Handling in C++

This page might seem like it duplicates some of what we have just seen, but it is valuable because it gives a different perspective on the topic. Read chapter 1 on pages 15-60.

Cleaning up

Function–level try blocks

Since constructors can routinely throw exceptions, you might want to handle exceptions that occur when an object's member or base subobjects are initialized. To do this, you can place the initialization of such subobjects in a function-level try block. In a departure from the usual syntax, the try block for constructor initializers is the constructor body, and the associated catch block follows the body of the constructor, as in the following example:

//: C01:InitExcept.cpp {-bor}
// Handles exceptions from subobjects.
#include 
using namespace std;
 
class Base {
  int i;
public:
  class BaseExcept {};
  Base(int i) : i(i) { throw BaseExcept(); }
};
 
class Derived : public Base {
public:
  class DerivedExcept {
    const char* msg;
  public:
    DerivedExcept(const char* msg) : msg(msg) {}
    const char* what() const { return msg; }
  };
  Derived(int j) try : Base(j) {
    // Constructor body
    cout << "This won't print" << endl;
  } catch(BaseExcept&) {
    throw DerivedExcept("Base subobject threw");;
  }
};
 
int main() {
  try {
    Derived d(3);
  } catch(Derived::DerivedExcept& d) {
    cout << d.what() << endl;  // "Base subobject threw"
  }
} ///:~

Notice that the initializer list in the constructor for Derived goes after the try  keyword but before the constructor body. If an exception does occur, the contained object is not constructed, so it makes no sense to return to the code that created it. For this reason, the only sensible thing to do is to throw an exception in the function-level catch clause.

Although it is not terribly useful, C++ also allows function-level try blocks for any function, as the following example illustrates:

//: C01:FunctionTryBlock.cpp {-bor}
// Function-level try blocks.
// {RunByHand} (Don't run automatically by the makefile)
#include 
using namespace std;
 
int main() try {
  throw "main";
} catch(const char* msg) {
cout << msg << endl;
return 1;
} ///:~

In this case, the catch block can return in the same manner that the function body normally returns. Using this type of function-level try block isn't much different from inserting a try-catch around the code inside of the function body.