Back to C++
2026-04-065 min read

C++ Exception Handling

Learn C++ Exception Handling step by step with clear examples and exercises.

Why This Matters

Welcome to this in-depth guide on C++ Exception Handling! We'll dive into the world of error management, covering practical scenarios, real-life bugs, and interview-ready techniques. By the end of this lesson, you'll be well-equipped to handle runtime errors and abnormal conditions with ease.

Why This Matters

Exception Handling in C++ is crucial for maintaining program stability by preventing unexpected termination. It allows a program to continue execution smoothly even when faced with errors, ensuring that your code remains robust and reliable. In real-world programming scenarios, it's essential to be able to handle exceptions effectively to avoid crashes and ensure the best possible user experience.

Prerequisites

Before diving into C++ Exception Handling, you should have a solid understanding of:

  1. Basic C++ syntax (variables, functions, loops, etc.)
  2. Data structures like arrays and vectors
  3. Object-Oriented Programming (OOP) concepts (classes, objects, inheritance, etc.)
  4. Standard Template Library (STL) components such as iterators and algorithms

Core Concept

Exception Handling in C++ involves the use of try-catch blocks to handle runtime errors gracefully. The try block contains code that might throw an exception, while the catch block handles the exception if it occurs.

#include <iostream>
using namespace std;

int main() {
int n = 10;
int m = 0;

try {
if (m == 0) throw "Division by zero";
cout << "Answer: " << n / m;
} catch (const char* msg) {
cout << "Error: " << msg;
}

return 0;
}

In the above example, if m is zero, the program throws an exception containing the message "Division by zero". The catch block catches this exception and prints the error message instead of causing the program to crash.

Internal Working of try-catch Block

When an exception occurs:

  1. The runtime executes code inside the try block.
  2. If an exception is thrown, the remaining code inside the try block is skipped.
  3. The runtime searches for a matching catch block.
  4. If found, the exception is handled.
  5. If no matching handler is found, terminate() is called, which terminates the program abruptly. During this process, stack unwinding occurs and local objects are destroyed automatically.

throw Keyword

The throw keyword is used to explicitly throw an exception. For example:

void checkAge(int age) {
if (age < 18) throw "Age must be 18 or above";
}

int main() {
try {
checkAge(15);
} catch (const char* msg) {
cout << msg;
}
return 0;
}

In this example, the function checkAge() throws an exception if the input age is less than 18. The catch block in the main() function catches and prints the error message.

Exception Hierarchy

Most standard exceptions in C++ derive from the std::exception class. Types of Exceptions include:

  1. Built-in Exceptions (throwing primitive data types like int, char, or float)
  2. Standard Exceptions (a hierarchy of standard exception classes defined in ` and `)
  3. Custom Exceptions (created when standard exceptions are insufficient)

Worked Example

Let's consider a simple example where we want to validate user input for a function that calculates the square root of a number. We'll use exception handling to handle invalid inputs gracefully.

#include <iostream>
#include <exception>
#include <cmath>

class InvalidInputException : public std::runtime_error {
public:
InvalidInputException(const char* msg) : std::runtime_error(msg) {}
};

double squareRoot(double number) {
if (number < 0) throw InvalidInputException("Invalid input: Number must be non-negative");
return sqrt(number);
}

int main() {
try {
double num = -1;
cout << "Square root of " << num << ": " << squareRoot(num) << endl;
} catch (const InvalidInputException& e) {
cerr << "Error: " << e.what() << endl;
}
return 0;
}

In this example, we've created a custom exception class InvalidInputException that derives from std::runtime_error. The function squareRoot() throws an instance of this exception if the input number is negative. In the main() function, we catch and print the error message when an exception occurs.

Common Mistakes

  1. Forgetting to include necessary headers (e.g., `, `)
  2. Not catching the correct type of exception (e.g., trying to catch a custom exception with a generic catch block)
  3. Neglecting to handle exceptions, leading to program termination
  4. Improper use of the throw keyword (e.g., throwing non-exception objects)
  5. Not providing meaningful error messages in custom exceptions

Practice Questions

  1. Write a function that checks if a string is a valid email address and throws an exception if it's not.
  2. Modify the squareRoot() function to handle the case where the number to be squared is very large, causing overflow errors.
  3. Create a custom exception class for handling memory allocation failures in your program.

FAQ

  1. Why should I use exceptions instead of error codes or assertions? Exceptions provide a more flexible and user-friendly way to handle errors, as they allow the program to continue execution even when an error occurs. Error codes and assertions, on the other hand, can lead to complex error handling logic and may cause the program to terminate abruptly if an error is encountered.
  2. Can I create my own exception classes in C++? Yes! You can create custom exception classes that inherit from std::exception or any of its derived classes like std::runtime_error. This allows you to provide more specific and meaningful error messages when exceptions are thrown.
  3. What happens if an uncaught exception is not handled in a program? If an uncaught exception is not handled, the program will terminate abruptly with a call to std::terminate(), which may result in lost data or unexpected behavior. To avoid this, it's essential to catch exceptions and handle them appropriately.
  4. Is it possible to throw exceptions from constructors or destructors? No, you cannot throw exceptions directly from constructors or destructors because these functions are guaranteed to complete execution before the program terminates. However, you can throw exceptions from functions called within constructors or destructors.
  5. What is the difference between std::runtime_error and std::logic_error? Both std::runtime_error and std::logic_error are derived from std::exception, but they represent different types of errors. std::runtime_error is used for runtime errors that occur during program execution, while std::logic_error is used for logic errors, such as invalid arguments or illegal states in the program.
C++ Exception Handling | C++ | XQA Learn