Exception Handling in C++
Overview
Errors are the problems that occur in the program due to an illegal operation performed by the user or by the fault of a programmer.
Exception Handling is the process of handling errors and exceptions such that the normal execution of the system is not halted. Exception handling in c++ consists of three keywords namely- try, catch, and throw.
Errors in C++
Errors are the problems that occur in the program due to an illegal operation performed by the user or by the fault of a programmer, which halts the normal flow of the program. Errors are also termed as bugs or faults. There are mainly two types of errors in programming. Let us learn about both the errors:
a. Compile Time Errors
Compile Time Errors are those errors that are caught during compilation time. Some of the most common compile-time errors are syntax errors, library references, incorrect import of library functions and methods, uneven bracket pair(s), etc.
Example:
Output:
As we can see the compiler detected the compilation error, i.e. missing semi-colon.
b. Run-Time Errors
Run-Time Errors are those errors that cannot be caught during compilation time. As we cannot check these errors during compile time, we name them Exceptions. Exceptions can cause some serious issues so we should handle them effectively.
As we now know what exceptions are, let us now learn what is exception handling in C++.
Example:
Output:
What is Exception Handling in C++?
As we know exception(s) or error(s) hinder the normal execution flow of a program so exception handling in C++ is one of the most important topics. We can formally define exception handling as - Exception Handling is the process of handling errors and exceptions such that the normal execution of the system is not halted.
One of the most common run time exceptions can be 0 division error. When we try to divide a number by 0, then the program gets executed successfully but during compile time, we will face an error causing an application crash.
We use exception handling in C++ to separate the error handling code from the normal code. For exception handling in C++, the try-catch-finally block is used.
Syntax:
Why Exception Handling?
Exception handling in C++ separates error handling code from normal code to ensure that the normal execution of the program is not interrupted by errors or exceptions. Unlike using multiple if-else conditions to handle errors, exception handling improves code readability and maintainability by allowing developers to easily manage exceptional situations.
In C++, exception handling enables the creation of a hierarchy of exception objects, grouping exceptions in namespaces or classes, and categorizing exceptions according to their types.
Using exception handling in C++, we can throw any number of exceptions from a function but we can choose to handle some of the thrown exceptions. A program can throw both pre-defined as well as a custom exception(s) as per the need of the program. We will be taking the example of both the pre-defined as well as custom exceptions later in this article.
Errors and Exceptions can be of two types in C++.
- Compile Time Errors - those errors that are caught during compilation time.
- Run Time Errors - those errors that cannot be caught during compile time. As we cannot check these errors during compile time, we name them Exceptions.
Note: Exception handling in C++ can throw both the basic data type as well as user-defined objects as an exception. For throwing an exception in C++, we use the throw keyword.
Examples of Exception Handling in C++
Now as we have a basic understanding of exception handling, let us take some examples to understand the topic better.
We can throw exceptions using throw keyword in C++. Example:
Output:
Let us take another example. Suppose we are trying to develop a program that gives access to its users when the user's age is more than or equal to 18 years. We can also use if-else statements for this purpose, but let us do age checking using exception handling in C++.
Output:
Basic Keywords in Exception Handling
As we know errors and exceptions can hinder the normal flow of program execution, so we use exception handling. The exception handing in C++ is mainly performed using three keywords namely - try, catch, and throw.
Syntax:
Let us learn about these three in detail.
C++ try
The try block is used to keep the code that is expected to throw some exception. Whenever our code leads to any exception or error, the exception or error gets caught in the catch block. In simple terms, we can say that the try block is used to define the block of code that needs to be tested for errors while it is being executed.
Example: Suppose we are dealing with databases, we should put the code that is handling the database connection inside a try block as the database connection may raise some exceptions or errors.
C++ catch
The catch block is used to catch and handle the error(s) thrown from the try block. If there are multiple exceptions thrown from the try block, then we can use multiple catch blocks after the try blocks for each exception. In this way, we can perform different actions for the various occurring exceptions. In simple terms, we can say that the catch block is used to define a block of code to be executed if an error occurs in the try block.
Example: Let us take the same above example that we are dealing with the database. Now, if during the connection, there is an exception raised inside the try block, then there should be a catch block present to catch or accept the exception and handle the exception. The catch block ensures that the normal flow of the code is not halted.
Note:
- The try and catch blocks are used in pairs.
- We can have multiple catch blocks for one try statement.
C++ throw
The throw block is used to throw exceptions to the exception handler which further communicates the error. The type of exception thrown should be same in the catch block. The throw keyword accepts one parameter which is passed to the exception handler. We can throw both pre-defined as well as custom exception(s) as per the requirements.
Whenever we want to explicitly throw an exception, we use the throw keyword. The throw keyword is also used to generate the custom exception.
Let us take an example to understand the overall working and syntax of try, catch, and throw in exception handling in C++.
Output:
Note: In the above example, the cout (print) statement after the throw statement will never get executed because the control will be passed to the catch block right after the throw statement.
If we do not know the type of throw used in the try block, we can always use the "three dots" syntax (...) inside the catch block, which will handle any type of exception. Let’s see an example to understand the syntax and use case:
Output:
C++ Standard Exceptions
The C++ library has some built-in standard exceptions under the <exception> header which can be used in our program. The standard exceptions are arranged in a parent-child class hierarchy. Refer to the image shown below for better visualization.
Let us briefly discuss the standard exception classes in the next section.
C++ Exception Classes
Let us learn the hierarchal standard exception classes that come under exception handling in c++.
Class Name | Use Case |
---|---|
std::exception | std::exception is the parent class of all the standard C++ exceptions. So, it contains declarations and definitions of other exceptions. |
std::bad_alloc | std::bad_alloc is the type of exception thrown by the allocation functions to report failure to allocate storage. |
std::bad_cast | std::bad_cast is the type of exception thrown when a dynamic_cast to a reference type fails the run-time check. |
std::bad_exception | std::bad_exception is used to handle unexpected exceptions in a C++ program. |
std::bad_typeid | std::bad_typeid is the type of exception thrown when a typeid operator is applied to a dereferenced null pointer value of a polymorphic type. |
std::logic_error | std::logic_error exception is the type of exception that can be theoretically detected by reading the code. |
std::domain_error | std::domain_error is the type of exception thrown when a mathematically invalid domain is used. |
std::invalid_argument | std::invalid_argument is the type of exception thrown due to invalid arguments. |
std::length_error | std::length_error is the type of exception thrown when a too big std::string is created. |
std::out_of_range | std::out_of_range is the type of exception that report errors when we are trying to access elements which is outside of the defined range. |
std::runtime_error | std::runtime_error exception is the type of exception that theoretically cannot be detected by reading the code. |
std::overflow_error | std::overflow_error exception is the type of exception thrown if a mathematical overflow occurs. |
std::underflow_error | std::underflow_error exception is the type of exception thrown if a mathematical underflow occurs. |
std::range_error | std::range_error is the type of exception thrown when a value is out of the valid range for a specific operation or when an index exceeds the bounds of a container or array. |
User-Defined Exceptions in C++
So far we have learned different subtopics of exception handling in C++. But we have not created our own (custom) exception.
Custom exception or user-defined exception is the type of exception that is not defined in the standard libraries of C++. So, we can use the C++ std::exception class to define objects that can be thrown as exceptions. The std::exception class provides a virtual member function called what(). The what() function returns a null-terminated character sequence (string) of type const char*. It can be overridden in derived classes to provide a custom description or depiction of the exception.
Let us create a custom exception to see how custom exceptions are treated in exception handling in C++.
Output:
Conclusion
- Compile Time Errors are those errors that are caught during compilation time.
- Run-Time Errors are those errors that cannot be caught during compilation time. As we cannot check these errors during compile time, we name them Exceptions.
- Exception Handling is the process of handling errors and exceptions such that the normal execution of the system is not halted.
- The main aim of Exception handling in C++ is to separate the error handling code from the normal code.
- Exception handling in C++ can throw both the basic data type as well as user-defined objects as exceptions. For throwing an exception in c++, we use the throw keyword.
- The try block is used to keep the code that is expected to throw some exception.
- The catch block is used to catch and handle the error(s) thrown from the try block. If we have multiple exceptions thrown from the try block, then we can use multiple catch blocks for different exceptions.
- The throw block is used to throw exceptions to the exception handler which further communicates the error. The throw keyword accepts one parameter which is passed to the exception handler.