C++ Reference Material
Exception Handling
Whenever you write a program that "goes into production" (people buy and use it), you probably expect that most of the time the program will start up, will have typical input, and will produce typical output. However, all software may be subject to misuse, whether deliberate or inadvertent, and whether by malicious or inexperienced users, and good software is written to anticipate and deal with the kinds of problems that may be caused by this kind of usage.
It is difficult, if not impossible, for a developer to anticipate all the different kinds of errors that may occur when a piece of software is being used. Sometimes a program is used without incident for years and then one day simply "comes off the rails" when a particular combination of input values that it has not seen before and is not prepared to deal with is entered. Ideally a program will always respond gracefully when something goes wrong, even if the error causes a complete shutdown of the program.
When writing code, a C++ developer must always be concerned with the errors that may occur in class methods, or in free functions, and how these errors should be dealt with. There are several possibilities:
In earlier versions of high-level programming languages, error handling in programs was generally carried out using if-statements. The condition in the if was a check for an error of some kind, and the body of the if was the code for dealing with that particular error. The body of the else, if present, or the code following the if, would be the code containing the actions to be taken if that particular error did not occur. Depending on the number of potential errors being checked there could be a lot of if-statements, or a very large if-else construct simply to deal with a wide variety of possible errors, none of which occurred very often.
The problem with handling potential errors in this way is that the code for dealing with those errors is "mixed up" with the code for doing whatever the program is supposed to be doing most of the time. This causes "code bloat", and can make the reading and/or modifying of such programs much harder during the inevitable maintenance process.
We should make clear, however, that we do not wish to convey the impression that using if-statements to check for possible errors is "old-fashioned" and should no longer be employed. There are many situations, especially when only a few potential errors are being checked, that this approach is still perfectly adequate and the use of exception handling may be regarded as "overkill".
Most modern programming languages, including C++, have an "exception handling" mechanism for dealing with unusual or "exceptional" situations. In this case, as you might expect, there continues to be a check for possible errors (or "exceptional" situations), but instead of dealing with whatever has happened with code at the location where it happened, an "exception" is "thrown". This has the effect of transferring control to another program location, where the exception can be "caught" and dealt with at that location. This means that the exception-handling code for different exceptions can be grouped in a location away from the "normal" code, thus removing some of the "clutter" from the code doing the real work of the program and permitting "cleaner" code to be written.
The exception-handling mechanism requires, for each possible exceptional situation, that
We should also point out that this is not necessarily the answer to every programmer's prayers either, and like any useful technology it can easily be used more than it should be, used in situations where it shouldn't be used at all, and used improperly in situations where it is (and should be) used. In fact, those of you who are familiar with, or who have at least heard of, the notorious "goto statement" of early versions of many programming languages may have an uneasy feeling that exception handling is somewhat reminiscent of that infamous demon from days gone by, and you would not be far wrong. In fact, whenever control in a program is suddenly transferred to a "distant" location in the source code, one may be asking for trouble, especially when trying to read the code in order to understand or debug it.
Here is what a typical exception-handling setup looks like in C++, in generic form:
try { //code in which a problem of some kind might occur if (some problem of a particular kind occurs) throw an instance of ExceptionType1 which identifies this problem //more code in which a problem of some kind might occur if (some problem of another particular kind occurs) throw an instance of ExceptionType2 which identifies this problem //more code ... } catch (ExceptionType1 e) { //code for dealing with an exception of type ExceptionType1 } catch (ExceptionType2 e) { //code for dealing with an exception of type ExceptionType2 } //more of these "catch blocks" if more exceptions may be thrown from the "try block" ... //additional code that will be executed unless a catch block terminates the program
What we see here is the use of the three C++ keywords, namely try, throw, and catch, to form a construct for dealing with one or more possible exceptions.
The code that may give rise to the various possible exceptional circumstances is placed in a try block. Within that try block there will be tests for the various problems that may occur and, if a test proves positive, and exception will be thrown and caught by whichever catch block has a parameter matching the particular exception. This brief description oversimplifies the situation, of course, and you really need to see a program containing some exception-handling code in action to fully appreciate the above syntax and its effect. And of course there are some rules, guidelines and subtleties you should be aware of, and some of these are mentioned in the following section.
catch (...) { //code to handle whatever may be caught }can be used to catch an exception of any type, and thus can be used in a manner analogous to the default: option of a switch statement.