Exception Handling in C++ : Learn How to Perform with Examples

Updated on September 13, 2024

Article Outline

Ever had your C++ program crash unexpectedly? It’s frustrating, right?

 

Imagine you’ve written hundreds of lines of code only to have it stop working due to a tiny error.

 

That’s where exception handling in C++ comes in. It’s our way of managing errors and ensuring our program runs smoothly.

 

Exception handling in C++ is a way to manage errors gracefully. It catches errors as they happen and lets us decide what to do next. Instead of our program crashing, we can handle the problem gracefully. This process ensures that our codes remain robust and can recover from unexpected situations.

 

This blog will walk you through how to use exception handling in C++ with easy-to-follow examples.

Also read: C++ Tutorial

Best Practices for Implementing Exception Handling in C++ Code

Wondering how to make your exception handling better? Here are some tips:

 

  • Keep normal and error-handling code separate: This improves readability.
  • Use specific exceptions: Handle different error types appropriately.
  • Clean up resources: Ensure you release resources like memory and file handles.
  • Always catch exceptions by reference: This avoids slicing and handles polymorphic exceptions correctly.
  • Document your exceptions: Make it clear which exceptions your functions might throw.
  • Use RAII (Resource Acquisition Is Initialization): This ensures resources are released properly by tying them to the lifespan of objects.
*Image
Get curriculum highlights, career paths, industry insights and accelerate your technology journey.
Download brochure

Limitations and Challenges of Exception Handling in C++

Exception handling is powerful, but it has its limits:

 

  • Overhead: It can slow down your program.
  • Complexity: Misuse can make your code hard to read and maintain.
  • No enforcement: C++ doesn’t enforce exception handling, leading to inconsistent practices.
  • Unpredictable control flow: Exceptions can make the flow of control hard to follow.
  • Resource leaks: If not handled properly, exceptions can lead to resource leaks.
  • Not suitable for all errors: Sometimes, error codes might be a better choice, especially for simple functions.

Importance of Exception Handling in Modern C++ Development

Why bother with exception handling? It keeps our programs running. Without it, any error can stop our program dead in its tracks.

 

With exception handling, we can:

 

  • Keep the program running: Even if an error occurs, we can manage it and continue.
  • Improve readability: Separate error handling from the main code, making it cleaner.
  • Make debugging easier: Identify exactly where things went wrong.

 

For example, when dealing with user inputs, we can’t always predict what the user will enter. Exception handling helps manage unexpected inputs without crashing the program.

Types of Exceptions in C++: Compile-Time vs. Run-Time

Let’s break down the types of errors we might encounter.

Compile-Time Errors

These are errors detected by the compiler before the program runs.

 

They include:

 

  • Syntax errors: Missing semicolons or incorrect keywords.
  • Type errors: Mismatched data types.

 

Compile-time errors are usually easier to fix because the compiler points them out.

Run-Time Errors

These occur while the program is running. They are harder to predict and include:

 

  • Division by zero
  • Invalid memory access

 

We manage run-time errors with exception handling. They are unpredictable and can cause the program to crash if not handled properly.

Keywords in Exception Handling: try, catch, and throw

Now, let’s dive into the tools we use for exception handling in C++: try, catch, and throw.

Basic Syntax:

try { // code throw exception; } catch(exception e) { // code for handling exception }

Using the try Block to Test Code for Exceptions

 

The try block contains code that might throw an exception. Think of it as a test zone. If something goes wrong, the exception is thrown to a catch block.

 

Catching Exceptions with the catch Block

 

The catch block catches exceptions thrown by the try block. It allows us to handle errors without crashing the program.

 

Throwing Exceptions Using the throw Keyword

 

The throw keyword is used to throw an exception. When the throw statement is executed, the current function is terminated, and control is transferred to the nearest catch block.

Example:

#include<iostream> using namespace std; int main() { int y = 50; cout << "Entering the try block." << endl; try { cout << "Within the try block." << endl; // Throwing an exception if the value of y is less than or equal to 75. if (y <= 75) { // Throwing the value of y as an exception as y is less than or equal to 75. throw y; // This line will not be executed because of the throw statement above. cout << "This message will not be printed." << endl; } } // Catching the value of y thrown by the throw keyword from the try block. catch (int val) { cout << "Exception caught! Value of y: " << val << endl; } cout << "Continuing after the catch block." << endl; return 0; } Explanation:

 

Output:

Entering the try block.

Within the try block.

Exception caught! Value of y: 50

Continuing after the catch block.

Using the try Block to Test Code for Exceptions

Worried about your C++ program crashing at runtime? You’re not alone.

 

Many developers face the same issue. Exception handling in C++ is our safety net. It helps us catch and handle errors gracefully.

 

The try block is where we place the code that might throw an exception. Think of it as a safety zone. If something goes wrong, control moves to the catch block.

 

Here’s a simple example. Let’s write a program to divide two numbers. We’ll ask the user for input and use a try block to handle potential errors.

#include <iostream> #include <stdexcept>   double divide(int a, int b) { if (b == 0) { throw std::runtime_error("Division by zero"); } return static_cast<double>(a) / b; }   int main() { int num1, num2; std::cout << "Enter two numbers to divide: "; std::cin >> num1 >> num2;   try { double result = divide(num1, num2); std::cout << "Result: " << result << std::endl; } catch (const std::runtime_error& e) { std::cerr << "Error: " << e.what() << std::endl; return 0; }

In this code, the divide function checks if the denominator is zero. If it is, the function throws a runtime_error. The try block catches this error and prints a message.

Catching Exceptions with the catch Block

Caught in a loop trying to figure out where your program went wrong? Catch blocks are your friend. They catch exceptions thrown by the try block and handle them.

 

The catch block follows the try block. It catches exceptions based on their type. If an exception matches the type in the catch block, the code inside runs.

 

Let’s extend our previous example to catch different types of exceptions.

#include <iostream> #include <stdexcept> double divide(int a, int b) { if (b == 0) { throw std::runtime_error("Division by zero"); } return static_cast(a) / b; } int main() { int num1, num2; std::cout << "Enter two numbers to divide: "; std::cin >> num1 >> num2; try { double result = divide(num1, num2); std::cout << "Result: " << result << std::endl; } catch (const std::runtime_error& e) { std::cerr << "Runtime Error: " << e.what() << std::endl; } catch (...) { std::cerr << "Unknown Error occurred." << std::endl; } return 0; }

Here, we’ve added a generic catch block using ‘…’. It catches any exception not specifically handled by the previous catch blocks.

Throwing Exceptions Using the throw Keyword

Ever wonder how to signal an error in your code? That’s where the throw keyword comes in. It lets us throw an exception when something goes wrong.

 

When we throw an exception, we stop the current function and move control to the nearest catch block. This helps us handle errors immediately.

 

Let’s see another example. This time, we’ll check for negative numbers.

#include <iostream> #include <stdexcept> void checkPositive(int num) { if (num < 0) { throw std::invalid_argument("Negative number not allowed"); } std::cout << "Number is positive: " << num << std::endl; } int main() { int num; std::cout << "Enter a number: "; std::cin >> num; try { checkPositive(num); } catch (const std::invalid_argument& e) { std::cerr << "Error: " << e.what() << std::endl; } return 0; }

In this code, if checkPositive receives a negative number, it throws an invalid_argument exception. The catch block handles this exception.

Standard Exception Classes in C++ and Their Use Cases

Confused about which exceptions to use? C++ provides several standard exceptions. These help us handle common errors efficiently.

 

Here are some common standard exceptions:

common standard exceptions classes in c++

Using these standard exceptions makes our code more readable and maintainable. Let’s see a table summarizing these exceptions:

 

Exception Type Description Example Use Case
std::exception Base class for all standard exceptions. Catch-all handler
std::bad_alloc Thrown by new when memory allocation fails. new operator failure
std::bad_cast Thrown by dynamic_cast when it fails. dynamic_cast failure
std::bad_exception Used to handle unexpected exceptions. Used in exception handling
std::bad_typeid Thrown by typeid when applied to a dereferenced null pointer. Dereferencing null pointers
std::logic_error Base class for errors in program logic. Base class for logical errors
std::domain_error Thrown when a mathematically invalid domain is used. Math functions
std::invalid_argument Thrown when an invalid argument is passed. Invalid function arguments
std::length_error Thrown when a length exceeds its maximum allowable size. String length errors
std::out_of_range Thrown when an index is out of range. Array index errors
std::runtime_error Base class for errors detected during runtime. General runtime errors
std::overflow_error Thrown when an arithmetic overflow occurs. Integer overflow
std::range_error Thrown when a value is out of range. Container index out of bounds
std::underflow_error Thrown when an arithmetic underflow occurs. Floating-point underflow

 

Defining Custom Exceptions in C++

Ever needed to create a specific error message? Custom exceptions are the answer. They let us define unique error types tailored to our needs.

 

To define a custom exception, we inherit from ‘std::exception’ and override the ‘what’ method.

 

Creating custom exceptions helps us manage specific errors in a more descriptive way.

 

Here’s an example. We’ll create a custom exception for invalid user input.

#include <iostream> #include <exception>   class InvalidInputException : public std::exception { public: const char* what() const noexcept override { return "Invalid input provided"; } }; void checkInput(int value) { if (value < 0) { throw InvalidInputException(); } std::cout << "Valid input: " << value << std::endl; } int main() { int num; std::cout << "Enter a number: "; std::cin >> num; try { checkInput(num); } catch (const InvalidInputException& e) { std::cerr << "Error: " << e.what() << std::endl; } return 0; }

In this code, ‘InvalidInputException’ is a custom exception. If ‘checkInput’ receives a negative number, it throws this exception. The catch block then handles it.

Examples of Exception Handling in C++

Struggling to figure out how to handle errors in your C++ code?

 

Let’s dive into some practical examples. These will help you understand how to use exception handling effectively.

Example 1: Handling Division by Zero

Let’s start with a common issue – dividing by zero. This often causes programs to crash. We can handle this using exception handling.

#include <iostream> #include <stdexcept>   double divide(int a, int b) { if (b == 0) { throw std::runtime_error("Division by zero"); } return static_cast<double>(a) / b; }   int main() { int num1, num2; std::cout << "Enter two numbers to divide: "; std::cin >> num1 >> num2;   try { double result = divide(num1, num2); std::cout << "Result: " << result << std::endl; } catch (const std::runtime_error& e) { std::cerr << "Error: " << e.what() << std::endl; }   return 0; }

In this example, if the second number is zero, a runtime_error is thrown and caught, preventing a crash.

Example 2: Managing Invalid Array Index Access

Accessing an array out of its bounds can lead to serious issues. Let’s see how to handle this error.

#include <iostream> #include <stdexcept>   int getElement(int* arr, int size, int index) { if (index >= size) { throw std::out_of_range("Index out of range"); } return arr[index]; }   int main() { int arr[5] = {1, 2, 3, 4, 5}; int index; std::cout << "Enter index to access: "; std::cin >> index;   try { int element = getElement(arr, 5, index); std::cout << "Element at index " << index << ": " << element << std::endl; } catch (const std::out_of_range& e) { std::cerr << "Error: " << e.what() << std::endl; }   return 0; }

If the user enters an index out of the array’s range, the out_of_range exception is thrown and handled.

Example 3: Custom Exception for Invalid User Input

Sometimes, standard exceptions aren’t enough. Let’s create a custom exception for specific errors.

#include <iostream> #include <exception> class InvalidInputException : public std::exception { public: const char* what() const noexcept override { return "Invalid input provided"; } }; void checkInput(int value) { if (value < 0) { throw InvalidInputException(); } std::cout << "Valid input: " << value << std::endl; } int main() { int num; std::cout << "Enter a number: "; std::cin >> num; try { checkInput(num); } catch (const InvalidInputException& e) { std::cerr << "Error: " << e.what() << std::endl; } return 0; }

This custom exception helps us handle specific cases like negative input values.

Also Read: Mastering C++ Comments

Conclusion

Exception handling in C++ aids in error management and maintains the smooth operation of our programs.

 

We have covered the fundamentals of C++ exception handling in this blog. We started by comprehending the significance of exception handling and how it keeps program execution flowing smoothly.

 

We can gracefully manage errors by utilizing try, catch, and throw. Standard exceptions cover common mistakes, but custom exceptions can handle special instances.

 

By mastering these methods, we can make sure that our C++ programs are dependable, stable, and easy to use.

FAQs
Exception handling enables our program to effectively manage the runtime errors without disturbing the normal program flow.
Yes, it is possible to have more than one catch block to manage the exceptions thrown from a single try block.
A custom exception is a user-defined exception class. We create one by inheriting from the ‘std::exception’ class and overriding the ‘what’ method.
Standard exceptions are predefined in the C++ standard library. Examples include ‘std::runtime_error’, ‘std::out_of_range’, and ‘std::bad_alloc’.
Separating normal code from error-handling code improves readability and maintainability, making the code easier to understand and manage.

Updated on September 13, 2024

Link
left dot patternright dot pattern

Programs tailored for your success

Popular

Management

Data Science

Finance

Technology

Future Tech

Upskill with expert articles

View all
Hero Vired logo
Hero Vired is a leading LearnTech company dedicated to offering cutting-edge programs in collaboration with top-tier global institutions. As part of the esteemed Hero Group, we are committed to revolutionizing the skill development landscape in India. Our programs, delivered by industry experts, are designed to empower professionals and students with the skills they need to thrive in today’s competitive job market.
Blogs
Reviews
Events
In the News
About Us
Contact us
Learning Hub
18003093939     ·     hello@herovired.com     ·    Whatsapp
Privacy policy and Terms of use

|

Sitemap

© 2024 Hero Vired. All rights reserved