C++ exception handling
Exception handling in C++ is controversial among embedded software developers, as is the use of the language at all. The feature is designed to make code more readable by providing a cleaner way to handle error conditions. This article aims to clarify what the facility does and how overheads may be managed.
Although various aspects of the C++ language concern engineers, a particular one is exception handling ...
The Exception Handling System (EHS) in C++ has nothing to be with exceptions in the sense of being hardware interrupts. It is designed to handle exceptional situations that are detected by the software. The intention is to provide a controlled failure mode, where a smooth exit from some deeply nested function calls is required (without resorting to goto).
Figure. Exception Handling System (Source: Colin Walls)
The use of EHS is quite straightforward. Code that needs EHS activated during its execution is enclosed in a try block:
// code that calls library functions
A throw statement may be used by a (library) function to assert an exception, which is identified by means of a class (an int in this case):
Processing of the exception is performed by some code in a catch block. There is normally one catch block for each type of exception that may be asserted:
catch (int n)
// exception handling code
This seems quite neat and simple and does provide a way to write fairly readable code in which exception handling is needed. However, there are some key points that should make embedded developers wary:
- If you are going to use the EHS, the additional code must be incorporated (a compiler option) for the entire application. It is not obvious to the human reader (or the compiler) what functions might be called (indirectly) by the code in a try This additional code adds size and reduces execution performance.
- Many compilers default to including EHS code. This means that the unwitting user incorporates the overhead automatically, even if they have no intention of using the EHS. A compiler switch is normally available to activate or deactivate the EHS code generation.
Optimal Use of the EHS
If your application's exception handling needs are simple, there are two ways to deploy the EHS which reduce the overheads:
- Use a generic catch block (where the type is specified with "...") instead of one for each type of exception.
- Do not include any catch blocks at all. This results in the library function terminate() being called when an exception is thrown. This function can be customized.
A third way to help cut down on overhead: use the noexcept keyword or the nothrow attribute. These can be used when you know that, dynamically, a function and its callees will never throw something that is expected to be caught by the function's caller. In practice, they cut down on the extra code size needed for the unwind tables for those functions. This last approach is most flexible, as the EHS is activated, and imposing an overhead, only in the parts of the code where its functionality is actually required.
Although many developers shy away from using EHS, used with care, it may be beneficial to many designs. The overhead should be carefully measured.
Colin Walls has over thirty years experience in the electronics industry, largely dedicated to embedded software. A frequent presenter at conferences and seminars and author of numerous technical articles and two books on embedded software, Colin is an embedded software technologist with Mentor Embedded [the Mentor Graphics Embedded Software Division], and is based in the UK. His regular blog is located at: http://blogs.mentor.com/colinwalls. He may be reached by email at firstname.lastname@example.org