Exception Handling in C++ With try throw and catch

Discussion in 'C++' started by usmanmalik, Jan 13, 2014.

  1. usmanmalik

    usmanmalik New Member

    Joined:
    Dec 28, 2013
    Messages:
    19
    Likes Received:
    14
    Trophy Points:
    0
    While gathering requirements for a software product, we cannot cover all the use cases of the product. If software under development is simpler we might be able to make it fool proof from all angles but large enterprise software products are not easy to develop maintaining high standards of reliability and robustness.

    In order to develop a reliable and robust system, the most integral aspect is to handle all the errors that can possibly occur when system will be used by the end user. Errors, also known as exceptions in some modern languages, occur when one a system performs in a way that is not desired. We can say that an error has occurred if one of the following conditions becomes true.
    1. System doesn’t perform the function which it is supposed to perform.
    2. System performs such functions that it is not supposed to perform.
    3. System gets crash due to certain reason.
    4. System does not meet the performance criteria which it should meet.
    5. System does not act according to the requirement specification document.
    There are several reasons behind the occurrence of an error or exception. However, usually errors are categorized into two classes.

    Types of Error



    Errors can be broadly categorized into two types. We will discuss them one by one.
    1. Compile Time Errors
    2. Run Time Errors/ Exceptions.
    1. Compile Time Errors

    Compile time errors as evident from the name are the errors that are caught when you are compiling your code. These errors are not critical because they can be caught and handled before the product is shipped to customer. In fact, without removing these errors code is not compiled. A typical example of compile time errors is missing library reference, syntax error or incorrect class import. If you are using some advanced IDE like Visual Studio or Eclipse for developing your application, they will tell you the type and exact location of the compile time error in your code. For Example, if you forget to type a closing bracket in your code somewhere, the IDEs will highlight the location of the code with error and will also give you some information regarding the error and how to handle that error. This is why we say that compile time errors are not that critical.

    2. Run Time Errors / Exceptions

    Run time errors, also known as exceptions are the errors that are considered critical. These errors are particularly difficult to find and special test cases are written by the quality assurance engineer to uncover these errors. These errors cannot be caught at run time and if remain uncaught and untested can cause program to behave in an abnormal way when it is deployed in the user’s environment. There can be several reasons behind run time errors. For example, you develop a calculator’s program and user divides a number by zero; what will happen? Although the code had been successfully compiled, yet when user divides the number by zero an exception or run time error will occur and our application will be crashed. This is due to the reason that we have not specified in our code that what should happen when a user divides a number by zero. In simpler words we have not handled this run time error or exception. C++ provides a mechanism using which we can handle most of the exceptions.

    Error Handling



    Error Handling or Exception handling is the process of handling errors and exceptions in such a way that they do not hinder normal operation of the system. Also, using error handling mechanism you can prevent user from seeing complex technical error messages, rather you can display more professional and non-technical messages to the users.

    Let us take a sample program where we take numerator and denominator from the user and then divided them and store the result in the third variable. We will see that when user enter 0 in denominator what happens. Look at Example1 for that.

    Example1
    Code:
    #include <iostream>
    #include <string>
    using namespace std;
    int main() {
    	int numerator, denominator, result;
    	cout <<"Enter the Numerator:";
    	cin>>numerator;
    	cout<<"Enter the denominator:";
    	cin>>denominator;
    	result = numerator/denominator;
    	cout<<"\nThe result of division is:" <<result;
    }
    
    See the output, when user enters 10 as numerator and 20 as denominator what happens.

    Output

    [​IMG]

    Exception

    [​IMG]

    An exception is occurred which shows a very weird message to the user. We do not want our user to see this message. In the first place we do not want our program to get crash we want to handle it in some way or the other.

    Now coming towards the more technical stuff; In C++, we have certain blocks that allow us to find and handle errors. Basically, there are three blocks that are integral to error handling in C++. In fact in other advanced languages such as Java and C#, you will frequently see these blocks being used for error handling purposes. Therefore, pay attention to them; it will help you in Java and C# as well if you do not know how to handle errors in C# and Java, if you have previously handled exceptions in C# and Java, the process is similar here. Following are the blocks.
    1. Try Block
    2. Catch Block
    3. Finally Block.
    1. Try Block

    Try block is basically a code block which surrounds the code where there is a chance of occurrence of error or exceptions. We enclose that piece of code within the try block. Syntax of catch block is very simple
    Code:
    try
    {
    	result = numerator/denominator;
    	cout<<"\nThe result of division is:" <<result;
    }
    
    Taking the code in Example1, we can enclose the above two lines in the try block. Try block has to send message to a corresponding catch block that an error can be occurred inside my body and if it occurs you will have to catch it.

    2. Catch Block

    Catch block executes only if an exception occurs inside the try block. When an exception occurs, a message is passed to the corresponding catch block along with some parameters. After, exception occurs, the statement in the corresponding catch block. All of our exception handling logic should be contained in the catch block. Remember, a try block will always be followed by a catch block. For example, if we want to show user that the denominator cannot be zero, we would do that in this block. In Example1, we can add catch block at the end of try block in following way

    Code:
    catch(int num) {
    	cout<<"You cannot enter "<<num<<" in denominator";
    }
    
    3. Throw Statement

    We have discussed that we pass a message from the catch block to try block that an exception has occurred and you will have to catch this exception. But how we send this message? We send this message from the try block to a catch block via special statement called ‘throw’. Throw statement basically throws the exception to catch block and passes the parameter to catch block. Throw statement cannot be declared outside the try block, it has to be inside the try block. We can modify the try block to include throw statement as follows.

    Code:
    try {
    	if(denominator == 0) {
    		throw denominator;
    	}
    	result = numerator/denominator;
    	cout<<"\nThe result of division is:" <<result;
    }
    In the above line of code, we have specified an if condition which states that if denominator is zero, an exception should be thrown using throw statement and we are passing denominator as the parameter to the catch block. Look back at the catch block, we specified an int num as the parameter in the catch block, therefore when exception with parameter denominator (Which is also an integer) will be thrown, it will be caught by the catch block which accepts integer parameter.

    Now, we will combine all the steps which we have studied above and will show you a working example of try catch block. We will modify Example1 to include try, catch blocks and throw statement to catch the exception when user divides a number by zero. Have a look at Example2.

    Example2

    Code:
    #include <iostream>
    #include <string>
    using namespace std;
    int main() {
    	int numerator, denominator, result;
    	cout <<"Enter the Numerator:";
    	cin>>numerator;
    	cout<<"Enter the denominator:";
    	cin>>denominator;
    	try {
    		if(denominator == 0) {
    			throw denominator;
    		}
    		result = numerator/denominator;
    		cout<<"\nThe result of division is:" <<result;
    	}
    	catch(int num) {
    		cout<<"You cannot enter "<<num<<" in denominator.";
    	}
    }
    The flow of code is simple, the user will enter numerator and denominator. If the denominator is zero, an exception will be generated using throw statement and the denominator will be passed as parameter with the exception. The only catch block we have accepts integer parameter, hence the control will be shifted to this block and the statements in the catch block will be executed. The output of Example2 is as follows.

    Output2

    [​IMG]

    Note: A very important to understand here is that if we have two or more than two catch blocks which accept integer parameter which catch block will execute. The answer is that the catch block which is defined earlier will catch that exception.

    Multiple Exceptions Handling using Multiple Catch blocks



    In Example2, we have one catch block because we threw only one exception. If we have more than one exception in our code, we will have to write multiple catch blocks in such scenarios. Suppose, a program can throw two exceptions, first exception has an integer parameter as in case of Example2 and there is one additional exception which has string as a parameter. In that case, we will to define two catch blocks, one which can accept integer as parameter and the other which can accept string as a parameter. We will explain this concept in Example3.

    Example3

    Code:
    #include <iostream>
    #include <string>
    using namespace std;
    int main() {
    	int numerator, denominator, result;
    	cout <<"Enter the Numerator:";
    	cin>>numerator;
    	cout<<"Enter the denominator:";
    	cin>>denominator;
    	try {
    		if(denominator == 0) {
    			throw denominator;
    		} else if (denominator < 0) {
    			throw "Negative denominator not allowed";
    		}
    		result = numerator/denominator;
    		cout<<"\nThe result of division is:" <<result;
    	}
    	catch(int num) {
    		cout<<"You cannot enter "<<num<<" in denominator.";
    	}
    	catch (char* message) {
    		cout<<message;
    	}
    }
    Note, in this example, we have two catch blocks: One which catches exception with parameter int and the other which catches exceptions with parameters string. In the try block, we have extended the ‘if’ statement and have added another condition that if the denominator entered by the user is negative, then an exception is thrown that contains the string that Negative Denominator is not allowed. In such case, the second catch statement will be executed which accepts the string as parameter. In this way we can handle exception of almost every type. The output of Example3 is as follows.

    Output3

    [​IMG]

    General Purpose Catch block for handling all exceptions



    In Example3, we have handled two exceptions but there can be hundreds of exceptions thrown by a program. It is not feasible and effective to handle all of the exceptions. It takes time and resources. Therefore, we handle only the most important and frequently occurring exceptions. For the rest of the exceptions, we have a catch block which is called general purpose catch block and it can handle all the exceptions. It do not require any parameter, instead in the parameter body of the catch block we write ‘. . .’ which mean that this catch block is common and can handle all the exceptions. As a rule of thumb, all the specialized catch blocks with parameters should be written first and at the end this general purpose catch block should be placed. This is due to the reason that if a specialized catch block exists for an exception, it should catch that exception and if no catch block exists to catch the exception, this general purpose catch block can still handle the exception and code doesn’t get crashed. Have a look at Example4.

    Example4

    Code:
    #include <iostream>
    #include <string>
    using namespace std;
    int main() {
    	int numerator, denominator, result;
    	cout <<"Enter the Numerator:";
    	cin>>numerator;
    	cout<<"Enter the denominator:";
    	cin>>denominator;
    	try {
    		if(denominator == 0) {
    			throw denominator;
    		} else if (denominator < 0) {
    			throw "Negative denominator not allowed";
    		}
    		result = numerator/denominator;
    		cout<<"\nThe result of division is:" <<result;
    	}
    	catch(...) {
    		cout<<"There is a problem performing calculation. Check your input again";
    	}
    }
    In Example4, we have removed both the catch blocks that accept integer and string as parameter and have instead added a general purpose catch block with parameters ‘…’ which shows it will catch all the exceptions. Now if the denominator is 0 or negative, in both the cases the generalized catch block will be executed and the statement “There is a problem performing calculation. Check your input again” will be printed.
     
    Last edited by a moderator: Jan 21, 2017
    shabbir likes this.
  2. rickealno

    rickealno New Member

    Joined:
    Jan 23, 2014
    Messages:
    1
    Likes Received:
    0
    Trophy Points:
    0
    Great piece of information; error handling is tedious, yet an important task for developer to write to handle errors. Well, I stumble across this website when browsing through error handling and I found it really helpful - mortoray.com/2013/12/05/is-exception-safe-code-truly-possible/
     

Share This Page

  1. This site uses cookies to help personalise content, tailor your experience and to keep you logged in if you register.
    By continuing to use this site, you are consenting to our use of cookies.
    Dismiss Notice