Back to C++
2026-02-275 min read

× (C++)

Learn × (C++) step by step with clear examples and exercises.

Title: Mastering Exception Handling in C++

Why This Matters

Exception handling is a crucial aspect of C++ programming that provides a robust way to manage runtime errors effectively. It allows developers to write cleaner, more efficient code by separating error-handling logic from the main program flow. This results in more reliable and easier-to-debug programs, especially when dealing with user input, file I/O, or complex algorithms where errors can occur unexpectedly.

Prerequisites

Before delving into exception handling, it is essential to have a solid understanding of the following concepts:

  1. Basic C++ syntax and control structures (e.g., loops, if-else statements)
  2. Understanding of classes and objects in C++
  3. Knowledge of function overloading and operator overloading
  4. Familiarity with file I/O operations in C++
  5. Adequate understanding of exception handling basics (if you're new to the topic, consider reading about it before proceeding)

Core Concept

Exception handling in C++ revolves around the try, catch, and throw keywords. The try block encompasses code that may potentially throw exceptions, while the catch block handles those exceptions when they occur. When an exception is thrown within a try block, control is transferred to the appropriate catch block for error handling.

Custom Exception Classes

Creating custom exception classes can be beneficial for better error messages and more specific handling of exceptions. To define a custom exception class, inherit from the std::exception base class:

#include <stdexcept>
class MyException : public std::exception {
public:
MyException(const char* message) : std::exception(message) {}
const char* what() const noexcept override {
return message;
}
private:
const char* message;
};

Throwing and Catching Exceptions

Here's a simple example of exception handling using custom exceptions:

#include <iostream>
#include "MyException.h"

void read_input(int& input) {
if (std::cin.peek() != '\n') {
throw MyException("Invalid input - expected newline");
}

if (!(std::cin >> input)) {
throw MyException("Invalid input - failed to read integer");
}
}

int main() {
int input;
try {
read_input(input);
// Rest of the code that uses the input...
} catch (const MyException& ex) {
std::cerr << "Error: " << ex.what() << '\n';
return 1;
}

return 0;
}

In this example, we define a custom exception class MyException. We then use it in our read_input function to handle invalid input scenarios. If the input is not a newline or an integer, an instance of MyException is thrown and caught by the corresponding catch block.

Worked Example

Let's implement a simple function that reads a file line by line and calculates the sum of its numbers:

#include <iostream>
#include <fstream>
#include <stdexcept>
#include <vector>
#include "MyException.h"

std::vector<int> read_numbers(const std::string& filename) {
std::ifstream file(filename);
if (!file.is_open()) {
throw MyException("Could not open file: " + filename);
}

std::vector<int> numbers;
int number;
while (file >> number) {
numbers.push_back(number);
}
if (file.peek() != EOF) {
throw MyException("Unexpected character found in file: " + filename);
}
return numbers;
}

int main() {
try {
const std::string filename = "numbers.txt";
auto numbers = read_numbers(filename);
int sum = 0;
for (const auto& number : numbers) {
sum += number;
}
std::cout << "Sum of numbers in " << filename << ": " << sum << '\n';
} catch (const MyException& ex) {
std::cerr << "Error: " << ex.what() << '\n';
return 1;
} catch (const std::exception& ex) {
std::cerr << "Error: " << ex.what() << '\n';
return 1;
}

return 0;
}

In this example, we define a function read_numbers that reads numbers from a file and returns them in a vector. If the file cannot be opened or an unexpected character is found, an exception is thrown using our custom MyException class. The main function calls read_numbers and calculates the sum of the numbers. If an exception occurs during the reading process, it is caught and handled by the corresponding catch block.

Common Mistakes

  1. Forgetting to include necessary headers (e.g., ``)
  2. Throwing exceptions without a matching catch block
  3. Not properly initializing exception objects (use std::runtime_error or custom exception classes)
  4. Failing to check for exceptions when calling functions that may throw exceptions
  5. Using raw pointers in the context of exception handling (avoid using raw pointers whenever possible)
  6. Neglecting to handle multiple types of exceptions with separate catch blocks
  7. Not properly declaring exception classes as noexcept or nothrow where appropriate
  8. Overusing exceptions for non-critical errors, leading to performance issues and cluttered code

Practice Questions

  1. Modify the read_numbers function to handle cases where the file contains non-numeric characters using a custom exception class.
  2. Implement a custom exception class for handling division by zero errors in C++.
  3. Write a function that calculates the factorial of a number using exception handling to ensure the input is positive and within a specific range.
  4. Create a custom exception class for handling file-related errors (e.g., unable to read from or write to a file) and use it in a program that reads and writes data to multiple files.
  5. Implement a function that validates user input using regular expressions and throws exceptions for invalid inputs.

FAQ

Q: What happens if an uncaught exception occurs?

A: If an uncaught exception occurs, the program terminates immediately with an error message.

Q: Can I catch exceptions of specific types?

A: Yes, you can use multiple catch blocks to handle exceptions of specific types.

Q: Is it a good practice to use exceptions for every potential error scenario?

A: No, excessive use of exceptions can lead to performance issues and make the code harder to read. Use exceptions judiciously for critical errors that require immediate attention.

Q: How do I properly declare exception classes as noexcept or nothrow?

A: To declare an exception class as noexcept, use the following syntax: class MyException : public std::exception { ... } noexcept(true);. To declare it as nothrow, use noexcept(false).

Q: How can I handle exceptions thrown by functions in a library or third-party code?

A: If you cannot modify the library's source code, you should catch and handle exceptions at the point of call. Be aware that this might not always be possible or practical, depending on the specific library and use case.

Q: What is the difference between std::runtime_error and std::logic_error?

A: std::runtime_error represents errors that occur during program execution, such as I/O errors or network failures. std::logic_error, on the other hand, represents logic errors, like division by zero or invalid argument values.

&times; (C++) | C++ | XQA Learn