OOP C12 Exceptions
Intro
Runtime Error
The basic philosophy of C++ is
Badly formed codes will not be run.
- There’s always something happening in run-time and
- It is very important to deal with all possible situation in the future running.
Example: Read files
Briefly reading a file means
- open the file;
- determine its size;
- allocate that much memory;
- read the file into memory;
- close the file;
There maybe many kinds of errors during the whole process. If we mark every kind of error an error code, the code may be complicated.
1 | |
With exception,
1 | |
At the point where the problem occurs, you
- might not know what to do with it;
- but do know that you must stop. And somebody, somewhere, must figure out what to do.
exception clean up error handling code: separates
- the codes that describes what you want to do
- from the codes that is executed.
Example: Invalid Index
In vector,
1 | |
What should the [] operator do if the index is not valid?
| method | notes | |
|---|---|---|
| 1 | Return random memory object | may be invalid |
| 2 | Return a special error value | for code like x = v[2] + v[4], the operator will continue to fail |
| 3 | Just exit | |
| 4 | Die gracefully (with autopsy!) | like assert |
Raise an exception
Class to represent the error
1 | |
Then the error could be thrown to mark the error.
1 | |
Caller Handling levels
-
Don’t Care: If code never even suspects a problem, then code never gets there.
1
2
3
4
5
6
7int func() {
Vector<int> v(12);
v[3] = 5;
int i = v[42]; // out of range and die
// control never gets here!
return i * 5;
} -
Mildly interested: warning but let the exception propagate.
1
2
3
4
5
6
7
8
9void outer2() {
String err("exception caught");
try {
func();
} catch (VectorIndexError) {
cout << err;
throw; // propagate the exception(re-raise)
}
} -
Cares Deeply: use
tryin the outer caller tofunc:1
2
3
4
5
6
7
8
9
10void outer() {
try {
func();
func2();
}
catch (VectorIndexError& e) {
e.diagnostic(); // This exception does not propagate
}
cout << "Control is here after exception";
} -
Doesn’t care about the particulars:
1
2
3
4
5
6
7void outer3() {
try {
outer2();
} catch (...) { // ... catches ALL exceptions!
cout << "The exception stops here!";
}
}
throw statement raises the exception
- Control propagates back to first handler for that exception (following the call chain)
- Objects on stack are properly destroyed
throw exp; throws value for matching, while throws;(valid only within a handler) re-raises the exception being handled.
Try Blocks
the try block takes form of
1 | |
- Any number of handlers accepted.
- No Handlers, No try block.
- It Costs cycles.
Exception handlers
A handler, taking a single argument (like a formal parameter)
- Selects exception by type
- could re-raise exceptions
1 | |
Handlers’ Checking
Handlers are checked in order of appearance.
- Check for exact match
- Apply base class conversions: Reference and pointer types, only
- Ellipsis (…) match all like
catch(...)
Inheritance can be used to structure exceptions!
1
2
3
4
5
6class MathErr { ...
virtual void diagnostic();
};
class OverflowErr : public MathErr { ... }
class UnderflowErr : public MathErr { ... }
class ZeroDivideErr : public MathErr { ... }The code is
1
2
3
4
5
6
7
8
9
10
11
12
13try {
// code to exercise math options
throw UnderFlowErr();
}
catch (ZeroDivideErr& e) {
// handle zero divide case
}
catch (MathErr& e) {
// handle other math errors
}
catch (...) {
// any other exceptions
}
Standard library exceptions
newraises abad_alloc()exception when failing.
1
2
3
4
5
6
7
8void func() {
try {
while(1) {
char *p = new char[10000];
}
}
catch (bad_alloc& e) { }
}

Exception specifications
Part of function prototypes.
1 | |
Declare which exceptions function might raise. A function with no Exception specifications may throw any type of exception.
- Exceptions are Not checked at compile time.
- If an exception not in the list propagates out at run time, the
unexpected exceptionis raised.
More exceptions
Exceptions and constructors
For failures in constructor:
- No return value is possible
- Use an
uninitialized flag - Defer work to an
Init()function
Two stages construction strategy
- Do normal work in constructor. Initialize
- all member objects
- all primitive members
- all pointers to 0
- Do addition initialization work in
Init()function: Those initializations requesting- File
- Network connection
- Memory
- …(any resource)
If the constructor can’t complete, better throw an exception.
- Destructors for those objects whose constructor didn’t complete won’t be called.
- Therefore Cleaning up allocated resources before throwing is neccesary.
Exceptions and destructors
Destructors are called when
- Normal call: object exits from scope
- During exceptions: stack unwinding invokes dtors on objects as scope is exited.
Design and usage with exceptions
Handlers