In real-world systems, things often go wrong. A bank server may become unreachable, a file may not open, or a user may enter invalid data. An exception is a runtime event that interrupts the normal flow of a program. Instead of crashing, the program “throws” an exception, which gives you a chance to respond.
Exception handling allows programmers to write applications that remain stable even if something unexpected happens.
Imagine you withdraw money from an ATM. If the machine runs out of cash, the system does not crash. Instead, it shows a message like “Unable to process request.” This is exception handling in action.
Basics of Exception Handling
Contents
- Basics of Exception Handling
- The try Block
- The catch Block
- The throw Statement
- Program 1: Division Calculator With Basic try/catch/throw
- Standard C++ Exception Types
- Using Standard Exceptions
- Creating Custom Exceptions
- Why Create Custom Exceptions?
- How to Define a Custom Exception
- Program 3: Custom Exception for Invalid Age
- Exception Propagation and Rethrowing
- Exception Propagation Example
- Resource Management and Exception Safety
- Example With File Handling
- Smart Pointers and Exception Safety
- Share this:
The try Block
A try block contains the code that might cause an exception.
try {
// risk code
}
catch(...) {
// handle risk
}
The catch Block
A catch block captures the exception. It must appear after the try block. You can use specific type catches, reference catches or catch-all.
The throw Statement
You use throw to manually create an exception when something unexpected occurs.
Program 1: Division Calculator With Basic try/catch/throw
#include <iostream>
using namespace std;
int main() {
int a, b;
cout << "Enter two numbers: ";
cin >> a >> b;
try {
if (b == 0)
throw "Division by zero!";
cout << "Result = " << (a / b) << endl;
}
catch (const char* msg) {
cout << "Error: " << msg << endl;
}
return 0;
}
Explanation: The program asks the user for two numbers. If the denominator is zero, we throw an exception. The catch block displays the error message without crashing the program.
Standard C++ Exception Types
C++ has a built-in hierarchy of exceptions based on std::exception. Some commonly used exception classes include std::runtime_error, std::out_of_range, std::invalid_argument, and std::bad_alloc.
Using Standard Exceptions
#include <iostream>
#include <vector>
#include <stdexcept>
using namespace std;
int main() {
vector<int> nums = {10, 20, 30};
try {
cout << nums.at(5);
}
catch (const out_of_range &e) {
cout << "Exception caught: " << e.what() << endl;
}
return 0;
}
Explanation: vector.at() throws an exception if the index is invalid. The catch block displays the standard exception message from e.what().
Creating Custom Exceptions
Why Create Custom Exceptions?
In bigger systems (e.g., Hospital Management, Banking Systems), domain-specific errors give clarity. Examples include LowBalanceException, InvalidAgeException, and FileCorruptException.
How to Define a Custom Exception
You create your own class that inherits from std::exception and override the what() function.
Program 3: Custom Exception for Invalid Age
#include <iostream>
#include <exception>
using namespace std;
class InvalidAge : public exception {
public:
const char* what() const noexcept override {
return "Age must be between 18 and 60.";
}
};
int main() {
int age;
cout << "Enter your age: ";
cin >> age;
try {
if (age < 18 || age > 60)
throw InvalidAge();
cout << "Age accepted!" << endl;
}
catch (const InvalidAge &e) {
cout << "Error: " << e.what() << endl;
}
return 0;
}
Explanation: Custom exception gives a meaningful message. If the user enters invalid age, the program does not terminate abruptly.
Exception Propagation and Rethrowing
Exceptions can move from one function to another. If a function cannot handle the error, it can simply throw it upward.
Exception Propagation Example
#include <iostream>
using namespace std;
void level3() {
throw "File not found!";
}
void level2() {
level3();
}
void level1() {
level2();
}
int main() {
try {
level1();
}
catch (const char* msg) {
cout << "Caught in main: " << msg << endl;
}
return 0;
}
Explanation: The exception thrown in level3() travels up through level2() and level1() until it is caught in main().
Resource Management and Exception Safety
One of the biggest reasons to use exception handling is protecting resources such as files, database connections, network sockets, and memory. C++ uses RAII (Resource Acquisition Is Initialization) to prevent resource leaks.
Example With File Handling
#include <iostream>
#include <fstream>
using namespace std;
class FileReader {
ifstream file;
public:
FileReader(const string &name) {
file.open(name);
if (!file)
throw "Unable to open file!";
}
~FileReader() {
cout << "Closing file..." << endl;
if (file.is_open())
file.close();
}
void display() {
string line;
while (getline(file, line))
cout << line << endl;
}
};
int main() {
try {
FileReader fr("data.txt");
fr.display();
}
catch (const char* msg) {
cout << "Exception: " << msg << endl;
}
return 0;
}
Smart Pointers and Exception Safety
#include <iostream>
#include <memory>
using namespace std;
int main() {
try {
unique_ptr<int> ptr(new int(10));
cout << "Value: " << *ptr << endl;
throw "Some error occurred!";
}
catch (const char* msg) {
cout << "Caught: " << msg << endl;
}
return 0;
}
Explanation: unique_ptr automatically frees memory even if an exception occurs, preventing memory leaks.

