Not only may a literal be thrown but it is also possible to throw a variable. For example see. except1b.cpp If a variable is thrown instead of a literal, it is passed by value to the catch() and the variable itself can not be passed not even as a reference. The reason for this situation is that the program leaves the function or block in which the variable is defined and therefore leaves the scope and the memory associated with it. In fact the stack associated with the program will be unwrapped. As a result, the variable would no longer be available for use outside of the try block.
In the example except1b.cpp the data value of the variable value was thrown. The value of the variable was passed to the argument of the catch() statement. However the data value does not have to be passed only the data type. By this is meant that the argument of the catch() statement may be the name of a data type rather than just a variable to receive the value. It catches the data type of the variable provided the data type of the variable and the data type of the signature of the catch() are the same. See. except1c.cpp. In this example the throw statement is:
throw value;
and the header of the catch() is:
catch(int)
This catch() will act because the data type of value is int. While the signature of the catch() can be just the data type, the throw statement can not throw a data type name. That is, it would not be possible for the throw statement to be the following:
throw int;
In the examples above, system literals or variables were thrown. However, it is also possible to throw a variable of a programmer data type like a class object as in except2.cpp. For example if you entered 9 and 5 for input to this program, the output would be:
Enter the dividend of the quotient: 9 Enter the divisor of the quotient: 5 The quotient is: 1.80
However, if you entered 4 & 0, the output is:
Enter the dividend of the quotient: 4 Enter the divisor of the quotient: 0 Error: Divided by zero.
In this last case the function quotient() threw the constructor/function: DivideByZeroError() that of course returns an object of the class: DivideByZeroError. The catch() has for a signature: DivideByZeroError() error that therefore receives the value of the object to the body of the catch(). The object will therefore have as a member the constant char pointer: message whose value is the string "Division by zero". Next the object calls the constant member function printMessage() that sends the message to the screen. Notice that the try{} block in this case is in the body of a member function of a class rather than being in the function main() as in the other examples. As this example demonstrates, it is possible to create classes that can be used in exception handling.
As stated above and as in the example except1a.cpp, if there is no specific catch() for the throw, the program can abort as in except3.cpp where there is no catch() to handle the exception.
The throw statement itself does not have to be in the try{} block. It can be in a function that is called in the try{} block. For example see except4.cpp in which there are several function calls within a throw that may be called under specific circumstances. The output of this program is:
Start of main() Inside of the try block Inside of MYTEST. The value is: 0 Inside of MYTEST. The value is 1. Caught the value 1. This is the end of main().
Notice that the try{} block ends when the function MYTEST() has as an argument 1 and then throws the value of the function's argument. The reason being that 1 can be considered the same as the Boolean true. Notice that the third call MYTEST(2) was not called because the program had terminated but without an abort.
Not only is it possible to have just one catch() but there can be several following the try{} block. For example see except5.cpp. Where the output will be:
Start of main() Caught the value 1 Caught the value 2 The message is Value is zero Caught the value 3 The end of main()
Observe in this example how try{} blocks may be used to treat problems and yet permit the program to continue without an abort.
In addition to specifying a catch() with a particular argument and therefore a specific type of throw, it is possible to have a default case type of a catch(). The construct of a default catch() is:
catch(…) { … }
In this case the three dots are required.
For example see: except6.cpp. The output is:
Start of main() Caught some value. Caught some value. Caught some value. The end of main()
This way of handling exceptions where all possible throws are sent to a default case is not an appropriate method of handling possible errors. A better way would be to have the default catch() be only one of the alternatives and the last one at that. For example see except7.cpp. If the default case was listed first, it would be called for each exception and none of the others would ever be called.
It is possible to have a throw without an argument. For example see: except9.cpp. The output of this program is:
Start of main() Caught USA inside of MYTEST() Inside of main() Caught USA inside of main() from a throw by MYTEST( ) The end of main()
In this example, the string "USA" is thrown to a catch() which in turn appears to throw nothing. That is the throw statement in the catch() has no argument. However the catch() statement actually throws the value which the first catch() statement caught. The second throw of the value: "FAU" is called a rethrow of the statement.
It is possible to have multiple try{} blocks to be nested. The objective of an inner try{} block may be to pass it on to another block if the exception can not be handled. One way of doing this as was seen in except9.cpp above is to use the statement:
throw;
Notice that this throw has no argument.