Object Oriented Programming in C++Unit 810 min read
Exception Handling in C++: Mechanisms, Syntax, and Real-World Applications
Unit 8 of Object Oriented Programming in C++ covers exception handling—how to detect, raise, and manage runtime errors gracefully using try, catch, and throw. Learn syntax, hierarchy, and best practices with code examples, real-world ties (e.g., bank transactions, file I/O), and exam-focused tips.
TAKEAWAYS:
- Exception handling isolates errors to prevent program crashes, using
tryblocks to test code andcatchblocks to handle exceptions. - C++ supports multiple
catchblocks for different exception types, checked in order of inheritance (derived → base). - Built-in exceptions (
std::exception) and custom exceptions (derived classes) enable structured error reporting. throwcan rethrow exceptions or propagate them up the call stack.- Best practices include avoiding
catch(...)for debugging, using RAII for resource cleanup, and documenting thrown exceptions.
Core Concepts and Syntax
1. Why Exception Handling?
Errors in programs (e.g., division by zero, file not found) disrupt normal flow. Exception handling:
- Separates error-handling code from business logic.
- Centralizes error management (e.g., logging, user notifications).
- Prevents crashes by gracefully recovering or exiting.
Example Scenario: A bank app (like Ncell Money) processes transactions. If a user’s account balance is insufficient, the app should not crash but instead show a message and roll back the transaction.
2. Key Components
flowchart TD
A["try block"] -->|"throws exception"| B["catch block"]
B --> C["Exception object"]
C --> D["Handled or rethrown"]
A -->|"no exception"| E["Continue execution"]tryblock: Code that might throw an exception.throw: Explicitly raises an exception (e.g.,throw runtime_error("Insufficient funds");).catchblock: Handles exceptions of a specific type.- Exception object: Contains error details (e.g., message, error code).
3. Syntax Rules
#include <iostream>
#include <stdexcept> // For std::exception
using namespace std;
int main() {
try {
// Risky code (e.g., division, file I/O)
int balance = 100;
int withdrawal = 150;
if (withdrawal > balance) {
throw runtime_error("Insufficient balance");
}
balance -= withdrawal;
}
catch (const runtime_error& e) {
// Handle the exception
cerr << "Error: " << e.what() << endl;
}
catch (const exception& e) {
// Catch base-class exceptions (e.g., logic_error, runtime_error)
cerr << "Generic error: " << e.what() << endl;
}
return 0;
}
Key Notes:
- Order matters: Catch derived classes before base classes (e.g.,
runtime_errorbeforeexception). const&: Avoid copying the exception object; pass by reference.- Multiple
catch: Handle specific exceptions first, then generic ones.
Visual: Exception Hierarchy in C++
classDiagram
class Exception {
<<abstract>>
+virtual void what() const = 0
}
class runtime_error {
+what() const
}
class logic_error {
+what() const
}
class bad_alloc {
+what() const
}
Exception <|-- runtime_error
Exception <|-- logic_error
Exception <|-- bad_allocBuilt-in Exceptions:
| Exception Class | When Thrown | Example |
|---|---|---|
runtime_error |
Logic errors (e.g., invalid args) | throw runtime_error("File not found"); |
logic_error |
Programmer errors (e.g., bad logic) | throw logic_error("Index out of bounds"); |
bad_alloc |
Memory allocation fails | new throws this if memory is exhausted. |
out_of_range |
Container access violations | vector::at() throws this. |
Worked Example: File Handling with Exceptions
Scenario: A program reads a file (e.g., eSewa’s transaction log). If the file is missing, it should notify the user instead of crashing.
#include <fstream>
#include <iostream>
using namespace std;
void readFile(const string& filename) {
ifstream file(filename);
if (!file) {
throw runtime_error("Failed to open file: " + filename);
}
string line;
while (getline(file, line)) {
cout << line << endl;
}
}
int main() {
try {
readFile("transactions.txt");
}
catch (const runtime_error& e) {
cerr << "Error: " << e.what() << endl;
// Alternative: Log to a backup file or notify admin.
}
return 0;
}
Trace Table:
| Step | Action | Exception Thrown? | Output |
|---|---|---|---|
| 1 | readFile("transactions.txt") |
Yes (file missing) | cerr prints error message. |
| 2 | catch block executes |
No | Program continues gracefully. |
Custom Exceptions
Why? Built-in exceptions may not fit your needs (e.g., a Daraz order system needs custom errors like OutOfStockException).
#include <stdexcept>
#include <string>
class OutOfStockException : public runtime_error {
public:
OutOfStockException(const string& product)
: runtime_error("Product " + product + " is out of stock") {}
};
void processOrder(const string& product) {
if (product == "iPhone 15") {
throw OutOfStockException(product);
}
// Proceed with order.
}
int main() {
try {
processOrder("iPhone 15");
}
catch (const OutOfStockException& e) {
cerr << "Order failed: " << e.what() << endl;
// Suggest alternatives or notify customer.
}
return 0;
}
Visual: Custom Exception Hierarchy
classDiagram
class OutOfStockException {
+OutOfStockException(string)
}
class runtime_error {
+what() const
}
OutOfStockException --|> runtime_error## In the Real World
eSewa/Khalti Transactions
- Idea Used: Exception handling for insufficient balance or failed payments.
- How: If a user’s account lacks funds, the app throws a
InsufficientFundsExceptionand shows a message instead of crashing. The transaction is rolled back.
Daraz Order Processing
- Idea Used: Custom exceptions for out-of-stock items or shipping failures.
- How: When a product is unavailable, Daraz throws an
OutOfStockExceptionand suggests alternatives. The order queue skips the item automatically.
Bank Loan Calculations (e.g., NMB Bank)
- Idea Used: Handling invalid interest rates or division by zero (e.g., 0% rate).
- How: A function like
calculateEMI()throws aInvalidRateExceptionif the rate is negative, ensuring the program doesn’t proceed with incorrect data.
WhatsApp Message Delivery
- Idea Used: Network exceptions (e.g.,
ConnectionFailedException). - How: If WhatsApp can’t connect to a server, it retries or shows an offline message, using exceptions to separate retry logic from core messaging.
- Idea Used: Network exceptions (e.g.,
Advanced Topics
1. Exception Specifications (Deprecated in C++11)
Old syntax (avoid in modern C++):
void riskyOperation() throw (runtime_error, bad_alloc) {
// May throw only runtime_error or bad_alloc.
}
Replacement: Use noexcept (C++11+):
void safeOperation() noexcept {
// Guaranteed not to throw.
}
2. Stack Unwinding
When an exception is thrown:
- The
tryblock exits. - Destructors of local objects are called (RAII ensures cleanup).
- The exception propagates up the call stack until caught.
Example:
void openFile() {
FileHandler fh; // RAII: destructor closes file.
if (!fh.open()) throw runtime_error("File open failed");
}
void process() {
try {
openFile();
}
catch (...) {
// fh's destructor runs here, closing the file.
}
}
3. Rethrowing Exceptions
Use throw; to propagate an exception up the stack (add context without losing the original error).
void readData() {
try {
// Code that throws.
}
catch (const exception& e) {
cerr << "Read error: " << e.what() << endl;
throw; // Rethrow to let caller handle it.
}
}
Common Pitfalls and Best Practices
| Pitfall | Solution |
|---|---|
Catching by value (catch (exception e)) |
Use catch (const exception& e) to avoid copies. |
Empty catch blocks |
Log the error or rethrow. |
Catching ... for debugging |
Use specific exceptions; catch(...) hides errors. |
| Not documenting thrown exceptions | Add comments like // Throws: runtime_error if file missing. |
| Ignoring exceptions in destructors | Destructors should not throw (use noexcept). |
## Exam Tip
Define Exception Handling:
"Exception handling in C++ is a mechanism to handle runtime errors gracefully using
try,throw, andcatchblocks, separating error-handling code from normal logic."Programming Questions:
- Must-do: Write a program with:
- A
tryblock containing risky code (e.g., division, file I/O). - At least two
catchblocks (one specific, one generic). - A
throwstatement with a custom or built-in exception.
- A
- Example Starter:
#include <iostream> using namespace std; int divide(int a, int b) { if (b == 0) throw runtime_error("Division by zero"); return a / b; } int main() { try { cout << divide(10, 0) << endl; } catch (const runtime_error& e) { cout << "Error: " << e.what() << endl; } return 0; }
- Must-do: Write a program with:
Theory Questions:
- Explain multiple
catchblocks and their order. - Differentiate between
throwandcatch. - Describe stack unwinding and RAII’s role.
- Explain multiple
Real-World Tie:
- In exams, relate exceptions to systems you know (e.g., "How would you handle a failed login in Khalti?").
- Use bank loan calculations or file operations as examples.
Avoid:
- Using
catch(...)without logging (marks deducted). - Throwing exceptions in destructors.
- Not handling base-class exceptions after derived ones.
- Using
Key Formula to Remember:
try {
// Risky code
}
catch (derived_exception& e) {
// Handle derived first
}
catch (base_exception& e) {
// Handle base
}
catch (...) {
// Fallback (use sparingly)
}
Based on the PU BE Computer (PU) syllabus for Object Oriented Programming in C++, unit 8.
Discussion
Loading…