Exception
An exception is an unscheduled event that disrupts program execution; used to detect undefined instructions.
Example from my Biquadris project (shortened for conciseness)
Also see Exception Safety.
CS247
I didn’t really think about exceptions before, but if you want to be a 10x Developer, you need to recognize that exceptions significantly change control flow! We no longer have the guarantee of sequential execution.
You need to think very hard about Exception Safety.
Motivation
To first motivate this, you need to understand Error Handling. C++ enables error handling through the use of Exceptions.
V.at(100)
fetches V[100]
if the value exists, otherwise, throws an exception.
r
is just an object, class type isstd::our_of_range
(included in<stdexcept>
)- The
.what()
method returns a string describing the exception.
Force the programmer to deal with the error because the control flow jumps.
Vector knows the error happened but not how to fix it. We know how to fix it, but not how the error occurred.
To raise an exception ourself, we use the throw
keyword. We can throw any value, but keep in mind that <stdexcept>
has objects for common scenarios like out_of_range
, logic_error
, invalid_argument
.
Stack Unwinding
When an exception is raised, control flow steps. We search through the stack upwards looking for a handler for this type of exception. This is called Stack Unwinding. Destructors are run for objects stored on the stack during the process of stack unwinding.
If a handler is found, we jump to that point. If no handler is found, program crashes.
Example of stack unwinding:
- Main calls
h
,h
callsq
,q
callsf
, throws, stack unwinding throughq
,h
, jump tocatch
block in main.
Handling Multiple Errors
Multiple errors may be handled via multiple catch blocks.
Rethrowing Errors
One handler can also deal with part of an error, rethrow the exception to allow someone else to deal with it (Stack Unwinding occurs).
We can also rethrow the same exception for someone else to deal with.
Why here do I just say
throw
rather thanthrow e
?This wasn’t just an accident.
throw e
performs a copy in order to throw this exception- Remember that copy constructors (any type of constructor) cannot be virtual. Therefore, the static type is used for the copy
If you throw a range_error
and catch via std::exception&
catch block,
throw
rethrowsrange_error
throw e
catch astd::exception
copied from therange_error
, we lose the dynamic type.
Generally, catch blocks should catch by reference to avoid avoid copies.
catch(...)
vs catch(std::exception& e)
?
The professor introduced both syntaxes, I thought they were exactly the same thing. Turns out, there is a difference:
With exceptions, you can handle integers and other types (http://www.cplusplus.com/doc/tutorial/exceptions/). I guess, for example, you can throw 5
.
For example:
Destructor Exceptions
Never let a destructor throw an Exception!
Default behavior: Program immediately crashes.
We can allow exceptions thrown from destructors by tagging them noexcept (false)
, see noexcept.
For example,
Be careful with
noexcept(false)
DestructorsAs we know, when we throw an exception, Stack Unwinding occurs. During this process destructors are running for stack allocated objects. If one of these destructors throws, now we have 2 active exceptions!
- 2 active exceptions = program crash (this behavior cannot be changed)
Standard
<stdexcept>
errorsSome standard
<stdexcept>
errors include:
out_of_range
logic_error
invalid_argument
std::bad_alloc
 occurs when the new operator fails to allocate the requested space, more here