Exception Handling in C++ – Writing Robust Programs
Learn how to gracefully handle runtime errors using try, catch, and throw. Master standard exceptions, custom exceptions, and best practices for clean, maintainable error-handling code.
- What exception handling is and why it matters
- How to use try, catch, and throw effectively
- The standard exception classes in C++
- How to create custom exception classes
- Best practices for writing robust error-handling code
1What is exception handling?
In real-world software, things can go wrong: a file might not open, a network might fail, or an invalid value might sneak into your program. Exception handling is a key feature in C++ that allows you to gracefully manage such errors without crashing the entire program.
Rather than using return codes or flags, C++ lets you throw exceptions when something goes wrong, and catch them where you can respond appropriately.
2Basic syntax
try { // Code that may throw an exception } catch (exception_type variable) { // Code that handles the exception }
Example: Division by zero
#include <iostream> using namespace std; int divide(int a, int b) { if (b == 0) throw "Division by zero!"; return a / b; } int main() { try { int result = divide(10, 0); cout << "Result: " << result << endl; } catch (const char* msg) { cout << "Error: " << msg << endl; } return 0; }
3The throw keyword
You use throw to signal that an exception has occurred.
throw value; // value can be an int, string, object, etc.
Examples:
throw -1;– throws an intthrow "Invalid input";– throws a C‑stringthrow std::runtime_error("File not found");– throws a standard exception object
4The try and catch blocks
Put all code that might throw an exception inside a try block. The catch block handles the error.
Multiple catch blocks
try { throw 3.14; } catch (int e) { cout << "Caught int: " << e << endl; } catch (double e) { cout << "Caught double: " << e << endl; } catch (...) { cout << "Caught unknown exception." << endl; }
catch (...) block catches any exception type. It should be used as a last resort and placed after all other catch blocks.
5Standard exceptions in C++
C++ provides a set of predefined exception classes in the <stdexcept> header.
| Exception class | Description |
|---|---|
std::runtime_error | Errors that occur at runtime |
std::invalid_argument | Invalid argument passed to a function |
std::out_of_range | Index out of range (e.g., vector access) |
std::overflow_error | Arithmetic overflow |
std::underflow_error | Arithmetic underflow |
std::logic_error | Errors in program logic |
#include <iostream> #include <stdexcept> using namespace std; int main() { try { throw std::out_of_range("Index out of range!"); } catch (const std::exception& e) { cout << "Caught exception: " << e.what() << endl; } return 0; }
std::exception by reference (const std::exception&) avoids slicing and enables polymorphic behavior.
6Custom exception classes
You can define your own exception class by inheriting from std::exception.
class MyException : public std::exception { public: const char* what() const noexcept override { return "Custom exception occurred!"; } };
Use it like this: throw MyException();
what() member function to provide a descriptive error message. The noexcept specifier ensures it does not throw.
7Nested try-catch blocks
You can nest try-catch blocks for fine‑grained error handling. You can also rethrow an exception using throw;.
try { try { throw 100; } catch (int x) { cout << "Inner catch: " << x << endl; throw; // rethrow } } catch (...) { cout << "Outer catch." << endl; }
8Best practices
- Throw exceptions, don't return error codes – exceptions are more expressive and cannot be ignored accidentally.
- Use standard exceptions where possible – they are well-tested and familiar to other developers.
- Catch exceptions by reference – especially for objects, to avoid slicing.
- Avoid exception handling in performance‑critical code – only if not needed, because throwing and catching have overhead.
- Use RAII (Resource Acquisition Is Initialization) to avoid memory leaks on exceptions.
- Never throw exceptions from destructors – they can cause program termination.
9Key concepts check
- Write a function that divides two integers and throws an exception if the denominator is zero.
- Create a
try-catchblock that catches the exception and prints a friendly error message. - Define a custom exception class that inherits from
std::exceptionand overridewhat(). - Throw and catch your custom exception in a program.
Bonus: Use nested try-catch blocks to handle different exception types and rethrow one of them.
10Quiz yourself
Final thoughts
Exception handling in C++ allows you to write safer, more robust applications by properly managing unexpected runtime errors. It is essential in real‑world development where external inputs, resources, and logic can often go wrong.
Understanding how to use try, catch, and throw – along with proper exception design – is a fundamental part of writing professional‑grade C++ code.
