Object Oriented ProgrammingUnit 710 min read
Exception Handling: Errors, Try-Catch, and Program Recovery
Unit 7 of Object Oriented Programming teaches how to anticipate, catch, and recover from runtime errors in C++ using structured exception handling (try-throw-catch), built-in exceptions, and user-defined exceptions—with real-world examples from banking, e-commerce, and telecom systems.
TAKEAWAYS:
- Exception handling isolates errors to prevent program crashes by separating error-handling code from normal logic.
- Built-in exceptions (e.g.,
std::runtime_error) and user-defined exceptions (custom classes) can be thrown and caught. - The
tryblock contains risky code,catchblocks handle specific exceptions, andthrowpropagates errors upward. - Stack unwinding releases resources (e.g., file handles, memory) when exceptions propagate through function calls.
- Best practices include catching exceptions by reference (
catch(const std::exception& e)) and avoiding empty catch blocks.
What is Exception Handling?
Exception handling is a mechanism to manage runtime errors gracefully without crashing the program. It follows the E-A-T model:
- Error detection (e.g., division by zero, file not found).
- Action (throw an exception).
- Treatment (catch and handle the exception).
Why Use Exception Handling?
- Prevents abrupt termination: Programs continue running after errors.
- Improves maintainability: Error-handling code is centralized.
- Enhances robustness: Users get meaningful error messages (e.g., "Invalid input: age cannot be negative").
Types of Exceptions
Exceptions in C++ are categorized into three types:
| Type | Description | Example |
|---|---|---|
| Synchronous | Occur due to program logic (e.g., invalid input, arithmetic errors). | throw std::runtime_error("Invalid age"); |
| Asynchronous | Triggered by external events (e.g., hardware failure, network issues). | throw std::system_error(errno, "Disk full"); |
| Built-in | Provided by the C++ Standard Library (e.g., std::exception, std::logic_error). |
catch (const std::out_of_range& e) |
How Exception Handling Works
The syntax involves three keywords:
try: Encloses code that might throw an exception.throw: Propagates an exception (value, object, or string).catch: Handles the exception (can have multiple blocks for different exceptions).
Flowchart of Exception Handling
flowchart TD
A["Start"] --> B["Execute try block"]
B -->|"Exception thrown?"| C["Yes"]
C --> D["Search catch blocks (top to bottom)"]
D -->|"Match found?"| E["Yes"]
E --> F["Execute catch block"]
F --> G["Continue program"]
D -->|"No match"| H["Terminate program (unhandled)"]
B -->|"No exception"| GBuilt-in Exceptions
The C++ Standard Library provides exception classes in the <stdexcept> header:
| Exception Class | When Thrown | Example |
|---|---|---|
std::runtime_error |
General runtime errors (e.g., invalid arguments). | throw std::runtime_error("File not found"); |
std::logic_error |
Program logic errors (e.g., invalid state). | throw std::logic_error("Negative salary"); |
std::out_of_range |
Accessing beyond container bounds (e.g., vector::at()). |
catch (const std::out_of_range& e) |
std::invalid_argument |
Invalid function arguments. | throw std::invalid_argument("Age < 0"); |
User-Defined Exceptions
You can create custom exceptions by deriving from std::exception or using classes.
Example: Custom Exception for Bank Transactions
#include <iostream>
#include <stdexcept>
#include <string>
```figure
{"type":"tree","nodes":["BankException","InsufficientFunds","NegativeBalance","InvalidTransaction"],"caption":"Hierarchy of custom exceptions for banking operations (e.g., extending `RuntimeException`)."}
class InsufficientFunds : public std::runtime_error { public: InsufficientFunds(double balance, double amount) : std::runtime_error("Insufficient funds"), balance(balance), amount(amount) {}
double getBalance() const { return balance; }
double getAmount() const { return amount; }
private: double balance, amount; };
int main() { double accountBalance = 1000.0; double withdrawalAmount = 1500.0;
try {
if (withdrawalAmount > accountBalance) {
throw InsufficientFunds(accountBalance, withdrawalAmount);
}
std::cout << "Withdrawal successful. Remaining balance: "
<< (accountBalance - withdrawalAmount) << std::endl;
}
catch (const InsufficientFunds& e) {
std::cerr << "Error: " << e.what() << "\n"
<< "Available balance: " << e.getBalance() << "\n"
<< "Requested amount: " << e.getAmount() << std::endl;
}
return 0;
}
### Output:
Error: Insufficient funds Available balance: 1000 Requested amount: 1500
Stack Unwinding
When an exception is thrown, the program unwinds the call stack, releasing resources (e.g., closing files, freeing memory) until a matching catch block is found.
Visualization: Stack Unwinding
Best Practices for Exception Handling
- Catch by Reference: Avoid slicing (use
catch(const std::exception& e)). - Avoid Empty Catch Blocks: Log errors or rethrow (
throw;). - Use RAII: Ensure resources (e.g., file handles) are released via destructors.
- Prefer Standard Exceptions: Use
std::exceptionhierarchy unless custom logic is needed. - Document Exceptions: Specify which exceptions a function might throw.
Real-World Applications
1. eSewa (Nepal) – Payment Failures
- Idea Used: Exception handling for failed transactions.
- How: If a user’s card declines, eSewa throws a
PaymentFailedExceptionand prompts for an alternative method (e.g., Khalti or mobile banking). - Code Snippet:
try { processPayment(amount); } catch (const PaymentFailedException& e) { std::cout << "Payment failed: " << e.what() << "\nTry another method (Khalti/Ncell)." << std::endl; }
2. Pathao (Ride-Hailing) – Driver Unavailability
- Idea Used: Asynchronous exceptions for driver-side issues.
- How: If a driver cancels a ride, Pathao throws a
DriverUnavailableExceptionand reassigns the ride to another driver or notifies the user. - Trace:
Step 1: User requests ride. Step 2: System throws DriverUnavailableException. Step 3: Catch block reassigns ride or cancels order.
3. NTC (Electricity Billing) – Meter Reading Errors
- Idea Used: File handling + exceptions for corrupted data.
- How: If a meter reading file is corrupted, NTC’s system throws a
FileCorruptionExceptionand logs the error for manual review. - Example:
try { readMeterData("corrupted_file.txt"); } catch (const FileCorruptionException& e) { logError(e.what()); notifyTechnician(); }
Worked Example: File Handling with Exceptions
Scenario: A program reads student grades from a file. If the file is missing or corrupted, it throws an exception.
Code:
#include <iostream>
#include <fstream>
#include <stdexcept>
void readGrades(const std::string& filename) {
std::ifstream file(filename);
if (!file.is_open()) {
throw std::runtime_error("File not found: " + filename);
}
int grade;
while (file >> grade) {
std::cout << "Grade: " << grade << std::endl;
}
if (file.bad()) {
throw std::runtime_error("File corrupted: " + filename);
}
}
int main() {
try {
readGrades("grades.txt");
}
catch (const std::runtime_error& e) {
std::cerr << "Error: " << e.what() << std::endl;
std::cout << "Using default grades..." << std::endl;
}
return 0;
}
Step-by-Step Trace:
| Step | Action | State |
|---|---|---|
| 1 | readGrades("grades.txt") called |
File not found → throw runtime_error. |
| 2 | Exception propagates to main(). |
catch block executes. |
| 3 | Output: "Error: File not found..." | Program continues with default grades. |
Common Pitfalls and How to Avoid Them
| Pitfall | Solution |
|---|---|
Catching all exceptions with catch(...) |
Use specific exception types for better debugging. |
| Throwing exceptions in destructors | Destructors should not throw; use noexcept. |
| Ignoring exceptions | Always handle or log exceptions to avoid silent failures. |
| Using exceptions for flow control | Exceptions are for error handling, not normal program logic (use if-else). |
Exam Tip
- Define Exception Handling: Start with "Exception handling is a mechanism to handle runtime errors gracefully using
try,throw, andcatchblocks." - Compare Built-in vs. User-Defined:
- Built-in:
std::runtime_error,std::logic_error. - User-defined: Derive from
std::exceptionor use custom classes.
- Built-in:
- Code Structure:
- Always show a
try-catchblock with a realistic example (e.g., file I/O, arithmetic). - Include one custom exception in your answer.
- Always show a
- Stack Unwinding: Mention that resources are released during unwinding.
- Real-World Link: Relate to eSewa/Khalti (payments), Pathao (rides), or NTC (billing) in your examples.
graph TD A["try block"] -->|"Exception thrown"| B["throw"] B --> C["catch block 1"] C -->|"No match"| D["catch block 2"] D -->|"No match"| E["Terminate (unhandled)"] C -->|"Match"| F["Handle exception"] F --> G["Program continues"]
Based on the TU BIT syllabus for Object Oriented Programming (BIT153), unit 7.
Discussion
Loading…