Guide | C++

How to Handle Exceptions in C++

How to Handle Exceptions in C++

When C++ code is executed, various types of errors can occur in the program - coding errors made by programmers, errors due to incorrect input or other unforeseen errors.

When an error occurs, C++ usually stops the program execution and generates an error message. In most scenarios, the preferred way to report and handle both logic and runtime errors is to use exceptions. Exceptions provide a formal and well-defined way for detecting errors and to pass the information up the call stack.

 

C++ Exception Types

C++ provides a list of standard exceptions defined in the <exception> class which can be used in code. These exceptions are arranged in a hierarchy:

C++ Exception Types Hierarchy
Figure 3: C++ Exception Types Hierarchy

As shown above, all the exception classes in C++ derive from the std::exception class. Here's a short description of each of the exceptions in the hierarchy above:

Table 1. C++ Exception Classes Under std::exception
Exception Description
std::exception Exception and parent class of all standard C++ exceptions.
std::bad_alloc Generally thrown by new.
std::bad_cast Generally thrown by dynamic_cast.
std::bad_typeid Generally thrown by typeid.
std::bad_exception Useful device to handle unexpected exceptions.
std::logic_failure Can be detected by reading code.
std::runtime_error Cannot be detected by reading code.
std::domain_error Thrown when using a mathematically invalid domain.
std::invalid_argument Thrown when using invalid arguments.
std::length_error Thrown when a large std::string is created.
std::out_of_range/td>

Thrown by the at method.
std::overflow_error Thrown when a mathematical overflow occurs.
std::range_error Thrown when attempting to store an out-of-range value.
std::underflow_error Thrown when a mathematical underflow occurs.

 

Throwing Exceptions in C++

Exceptions provide a way to react to exceptional circumstances in programs by transferring control to special functions called handlers. Exceptions are preferred in modern C++ over traditional error handling for the following reasons:

  • They force the calling code to identify error conditions and handle them. This prevents them from stopping program execution.
  • C++ destroys all objects in scope after an exception occurs, thereby reducing resource usage.
  • An exception provides a clean separation between the code that identifies an error and the code that handles the error.
  • Error types can be grouped together, which allows creating a hierarchy of exception objects, grouping them in namespaces or classes and categorizing them according to type.

An exception is thrown by using the throw keyword in C++. The throw keyword allows the programmer to define custom exceptions.

 

Throwing Exceptions in C++ Example

Here’s an example on how to use the throw keyword to throw an exception in C++:

double division(int num, int den) 
{
    if (den == 0) 
    {
        throw std::runtime_error("Error: Division by zero attempted");
    }
    return (num / den);
}

 

Handling Exceptions in C++

Exception handling in C++ is done using the try and catch keywords.

To catch exceptions, a portion of code is placed under inspection. This is done by enclosing this portion of code in a try block. When an exception occurs within the try block, control is transferred to the exception handler. If no exception is thrown, the code continues normally and the handlers are ignored.

Exception handlers are declared with the catch keyword, which is placed immediately after the try block. Multiple handlers (catch expressions) can be chained - each one with a different exception type. Only the handler whose argument type matches the exception type in the throw statement is executed.

C++ does not require a finally block to make sure resources are released if an exception occurs.

 

Handling Exceptions in C++ Example

The following example shows how to use try and catch to handle exceptions in C++:

#include <iostream>
#include <stdexcept>

using namespace std;

int AddPositiveIntegers(int a, int b)
{
    if (a < 0 || b < 0)
        throw std::invalid_argument("AddPositiveIntegers arguments must be positive");

    return (a + b);
}

int main()
{
    try
    {
        cout << AddPositiveIntegers(-1, 2);
    }

    catch (std::invalid_argument& e)
    {
        cerr << e.what() << endl;
        return -1;
    }

    return 0;
}

In this example, the AddPositiveIntegers() function is called from inside the try block in the main() function. The AddPositiveIntegers() expects two integers a and b as arguments, and throws an invalid_argument exception in case any of them are negative.

The catch block in the main() function catches the invalid_argument exception and handles it.

 

Track, Analyze and Manage Errors With Rollbar

Managing errors and exceptions in your code is challenging. It can make deploying production code an unnerving experience. Being able to track, analyze, and manage errors in real-time can help you to proceed with more confidence. Rollbar automates error monitoring and triaging, making fixing C++ errors easier than ever. Sign Up Today!