To catch exceptions, a portion of code is placed under exception inspection. This is done by enclosing that portion of code in a try-block. When an exceptional circumstance arises within that block, an exception is thrown that transfers the control to the exception handler. If no exception is thrown, the code continues normally and all handlers are ignored.
An exception is thrown by using the throw keyword from inside the try block. Exception handlers are declared with the keyword catch, which must be placed immediately after the try block:
1 | // exceptions #include <iostream> using namespace std;
int main () { try { throw 20; } catch (int e) { cout << "An exception occurred. Exception Nr. " << e << '\n'; } return 0; } | An exception occurred. Exception Nr. 20 |
|
The code under exception handling is enclosed in a try block. In this example this code simply throws an exception:
| throw 20; |
|
A throw expression accepts one parameter (in this case the integer value 20), which is passed as an argument to the exception handler.
The exception handler is declared with the catch keyword immediately after the closing brace of the try block. The syntax for catch is similar to a regular function with one parameter. The type of this parameter is very important, since the type of the argument passed by the throw expression is checked against it, and only in the case they match, the exception is caught by that handler.
Multiple handlers (i.e., catch expressions) can be chained; each one with a different parameter type. Only the handler whose argument type matches the type of the exception specified in the throw statement is executed.
If an ellipsis (...) is used as the parameter of catch, that handler will catch any exception no matter what the type of the exception thrown. This can be used as a default handler that catches all exceptions not caught by other handlers:
1 | try { // code here } catch (int param) { cout << "int exception"; } catch (char param) { cout << "char exception"; } catch (...) { cout << "default exception"; } |
|
In this case, the last handler would catch any exception thrown of a type that is neither int nor char.
After an exception has been handled the program, execution resumes after the try-catch block, not after the throw statement!.
It is also possible to nest try-catch blocks within more external try blocks. In these cases, we have the possibility that an internal catch block forwards the exception to its external level. This is done with the expression throw; with no arguments. For example:
1 | try { try { // code here } catch (int n) { throw; } } catch (...) { cout << "Exception occurred"; } |
|
| double myfunction (char param) throw (int); |
|
This declares a function called myfunction, which takes one argument of type char and returns a value of type double. If this function throws an exception of some type other than int, the function calls std::unexpected instead of looking for a handler or callingstd::terminate.
If this throw specifier is left empty with no type, this means that std::unexpected is called for any exception. Functions with no throw specifier (regular functions) never callstd::unexpected, but follow the normal path of looking for their exception handler.
1 | int myfunction (int param) throw(); // all exceptions call unexpected int myfunction (int param); // normal exception handling |
|
Standard exceptionsThe C++ Standard library provides a base class specifically designed to declare objects to be thrown as exceptions. It is called std::exception and is defined in the <exception> header. This class has a virtual member function called what that returns a null-terminated character sequence (of type char *) and that can be overwritten in derived classes to contain some sort of description of the exception.
1 | // using standard exceptions #include <iostream> #include <exception> using namespace std;
class myexception: public exception { virtual const char* what() const throw() { return "My exception happened"; } } myex;
int main () { try { throw myex; } catch (exception& e) { cout << e.what() << '\n'; } return 0; } | My exception happened. |
|
We have placed a handler that catches exception objects by reference (notice the ampersand & after the type), therefore this catches also classes derived from exception, like our myex object of type myexception.3. What are the Types of Errors?We face different kinds of errors. These errors can be categorized into five different types. These are like below −
Exception handling helps to manage the execution of program when an exception occurs during runtime in a systematic manner. Exception handing mechanism allows smooth execution of program. Exception handling mechanisms in C++ is basically done using three keywords, try, throw and catch.5. Explain Uncaught ExceptionUsually, the exception is handled by the try-catch block, but there are instances where there isn’t a matching catch block and the program just terminates. This terminate() function is modifiable as per user requirements.Example #include <exception>#include <iostream>using namespace std;//defining custom terminatorvoid myhandler(){ cout << "Inside new terminate handler\n"; abort();}int main(){ set_terminate(myhandler); try { cout << "Inside try block\n"; throw 100; } catch (char a){ cout << "Inside catch block\n"; } return 0;}OutputInside try blockInside new terminate handler6. Explain Using try and CatchException handling is performed using try/catch statement. The C++ try block is used to place the code that may occur exception. The catch block is used to handle the exception. Example without try/catch #include <iostream> using namespace std; float division(int x, int y) { return (x/y); } int main () { int i = 50; int j = 0; float k = 0; k = division(i, j); cout << k << endl; return 0; } Output:Floating point exception (core dumped) Try/catch example #include <iostream> using namespace std; float division(int x, int y) { if( y == 0 ) { throw "Attempted to divide by zero!"; } return (x/y); } int main () { int i = 25; int j = 0; float k = 0; try { k = division(i, j); cout << k << endl; }catch (const char* e) { cerr << e << endl; } return 0; } Output:Attempted to divide by zero!7. Explain Multiple Catch ClausesMultiple catch blocks are used when we have to catch a specific type of exception out of many possible type of exceptions i.e. an exception of type char or int or short or long etc. Let's see the use of multiple catch blocks with an example.
Multiple Catch Block Example #include<iostream> using namespace std; int main(){int a=10, b=0, c;try{ //if a is divided by b(which has a value 0); if(b==0) throw(c); else c=a/b; }catch(char c) //catch block to handle/catch exception{ cout<<"Caught exception : char type ";}catch(int i) //catch block to handle/catch exception{ cout<<"Caught exception : int type ";}catch(short s) //catch block to handle/catch exception{ cout<<"Caught exception : short type ";}cout<<"\n Hello";}Output is -: Caught exception : int type Hello
In this code, we have three catch blocks associated with one try block. At the runtime, compiler finds a division-by-zero problem, hence an exception of type int is thrown when a statement enclosed within the try block is executed.
This exception type is matched with the declared exception type in every catch-block(matching starts with the first catch block).
The catch block that matches with type of exception thrown is executed, while the rest of catch blocks are skipped. Let's see how -
Let's understand this by an example - #include<iostream> using namespace std; int main(){int a=10, b=0, c;try{ //if a is divided by b(which has a value 0); if(b==0) throw(c); else c=a/b; }catch(...) //catch block to handle/catch exception{ cout<<"A catch block for all types of exceptions has caught an exception";} }Output A catch block for all types of exceptions has caught an exceptionAs you may see in the code above, a single catch block defined with three dots (...) has caught all types of exceptions i.e. an exception of type int, without even declaring it. 8. Explain Nested Try StatementsWhen try blocks are nested and a throw occurs in a function called by an inner try block, control is transferred outward through the nested try blocks until the first catch block is found whose argument matches the argument of the throw expression.For example: try{ func1(); try { func2(); } catch (spec_err) { /* ... */ } func3();}catch (type_err) { /* ... */ } // if no throw is issued, control resumes here. In the above example, if spec_err is thrown within the inner try block (in this case, from func2()), the exception is caught by the inner catch block, and, assuming this catch block does not transfer control, func3() is called. If spec_err is thrown after the inner try block (for instance, by func3()), it is not caught and the function terminate() is called. If the exception thrown from func2() in the inner try block is type_err, the program skips out of both try blocks to the second catch block without invoking func3(), because no appropriate catch block exists following the inner try block.You use a try block to indicate which areas in your program that might throw exceptions you want to handle immediately. You use a function try block to indicate that you want to detect exceptions in the entire body of a function. try block syntax try{statements } handler Function try block syntaxtry:member_initializer_list function_body handler The following code is an example of a function try block with a member initializer, a function try block and a try block: #include <iostream>using namespace std; class E { public: const char* error; E(const char* arg) : error(arg) { }}; class A { public: int i; // A function try block with a member // initializer A() try : i(0) { throw E("Exception thrown in A()"); } catch (E& e) { cout << e.error << endl; }}; // A function try blockvoid f() try { throw E("Exception thrown in f()");}catch (E& e) { cout << e.error << endl;} void g() { throw E("Exception thrown in g()");} int main() { f(); // A try block try { g(); } catch (E& e) { cout << e.error << endl; } try { A x; } catch(...) { }} See the following output of the above example: Exception thrown in f()Exception thrown in g()Exception thrown in A()The constructor of class A has a function try block with a member initializer. Function f() has a function try block. The main() function contains a try block.9. Explain User Define Exception using ThrowThe new exception can be defined by overriding and inheriting exception class functionality.User-defined exception exampleLet's see the simple example of user-defined exception in which std::exception class is used to define the exception.
#include <iostream> using namespace std;
// One function works for all data types. // This would work even for user defined types // if operator '>' is overloaded template <typename T>
T myMax(T x, T y) { return (x > y) ? x : y; }
int main() {
// Call myMax for int cout << myMax<int>(3, 7) << endl;
// call myMax for double cout << myMax<double>(3.0, 7.0) << endl;
// call myMax for char cout << myMax<char>('g', 'e') << endl;
return 0; } |
#include <iostream> using namespace std;
template <typename T> class Array { private: T* ptr; int size;
public: Array(T arr[], int s); void print(); };
template <typename T> Array<T>::Array(T arr[], int s) { ptr = new T[s]; size = s; for (int i = 0; i < size; i++) ptr[i] = arr[i]; }
template <typename T> void Array<T>::print() { for (int i = 0; i < size; i++) cout << " " << *(ptr + i); cout << endl; }
int main() { int arr[5] = { 1, 2, 3, 4, 5 }; Array<int> a(arr, 5); a.print(); return 0; } |
#include <iostream> using namespace std;
template <class T, class U> class A { T x; U y;
public: A() { cout << "Constructor Called" << endl; } };
int main() { A<char, char> a; A<int, double> b; return 0; } |