try
Blocks and ConstructorsIn general, exceptions can occur at any point in the program’s execution. In particular, an exception might occur while processing a constructor initializer. Constructor initializers execute before the constructor body is entered. A catch
inside the constructor body can’t handle an exception thrown by a constructor initializer because a try
block inside the constructor body would not yet be in effect when the exception is thrown.
Exercise 18.4: Looking ahead to the inheritance hierarchy in Figure 18.1 (p. 783), explain what’s wrong with the following try
block. Correct it.
try {
// use of the C++ standard library
} catch(exception) {
// ...
} catch(const runtime_error &re) {
// ...
} catch(overflow_error eobj) { /* ... */ }
Exercise 18.5: Modify the following main
function to catch any of the exception types shown in Figure 18.1 (p. 783):
int main() {
// use of the C++ standard library
}
The handlers should print the error message associated with the exception before calling abort
(defined in the header cstdlib
) to terminate main
.
Exercise 18.6: Given the following exception types and catch
clauses, write a throw
expression that creates an exception object that can be caught by each catch
clause:
(a) class exceptionType { };
catch(exceptionType *pet) { }
(b) catch(...) { }
(c) typedef int EXCPTYPE;
catch(EXCPTYPE) { }
To handle an exception from a constructor initializer, we must write the constructor as a function try
block. A function try
block lets us associate a group of catch
clauses with the initialization phase of a constructor (or the destruction phase of a destructor) as well as with the constructor’s (or destructor’s) function body. As an example, we might wrap the Blob
constructors (§ 16.1.2, p. 662) in a function try
block:
template <typename T>
Blob<T>::Blob(std::initializer_list<T> il) try :
data(std::make_shared<std::vector<T>>(il)) {
/* empty body */
} catch(const std::bad_alloc &e) { handle_out_of_memory(e); }
Notice that the keyword try
appears before the colon that begins the constructor initializer list and before the curly brace that forms the (in this case empty) constructor function body. The catch
associated with this try
can be used to handle exceptions thrown either from within the member initialization list or from within the constructor body.
It is worth noting that an exception can happen while initializing the constructor’s parameters. Such exceptions are not part of the function try
block. The function try
block handles only exceptions that occur once the constructor begins executing. As with any other function call, if an exception occurs during parameter initialization, that exception is part of the calling expression and is handled in the caller’s context.
The only way for a constructor to handle an exception from a constructor initializer is to write the constructor as a function try
block.
Exercise 18.7: Define your Blob
and BlobPtr
classes from Chapter 16 to use function try
blocks for their constructors.