Exception Handling is a powerful feature in C++ that helps deal with runtime errors in a structured manner. Instead of letting errors disrupt the flow of the program, exceptions allow us to handle errors and recover from them without crashing the program.
In C++, exception handling is achieved using a combination of three keywords:
try: Defines a block of code in which exceptions can occur.throw: Used to throw an exception when an error is encountered.catch: Catches and handles the exception thrown by the throw keyword.The syntax for exception handling in C++ is as follows:
try {
// Code that may throw an exception
}
catch (exception_type1 ex1) {
// Handle exception_type1
}
catch (exception_type2 ex2) {
// Handle exception_type2
}
catch (...) {
// Handle any unknown exception
}
try Block: The code that might throw an exception is placed inside the try block.throw Statement: When a problem occurs in the try block, an exception is thrown using the throw keyword.catch Block: The catch block handles the exception, and the type of exception is specified to catch different exceptions.#include <iostream>
using namespace std;
int divide(int numerator, int denominator) {
if (denominator == 0) {
throw "Division by zero is not allowed!"; // Throwing an exception
}
return numerator / denominator;
}
int main() {
try {
int result = divide(10, 0); // Trying to divide by zero
cout << "Result: " << result << endl;
}
catch (const char* msg) { // Catching the thrown exception
cout << "Error: " << msg << endl;
}
return 0;
}
Explanation:
divide() function, if the denominator is 0, an exception is thrown with the message "Division by zero is not allowed!".main() function, the exception is caught by the catch block, and the error message is printed.Output:
Error: Division by zero is not allowed!
Exceptions in C++ can be of any type. The most common types are:
Predefined Exception Classes: C++ provides a hierarchy of exception classes.
std::exception: Base class for all standard exceptions.std::runtime_error: Derived from std::exception, used for errors that can occur during the program’s runtime.std::logic_error: Derived from std::exception, used for errors that occur due to logic problems (like invalid arguments).Custom Exceptions: You can also define your own exception classes by deriving them from std::exception or any other class.
#include <iostream>
#include <stdexcept> // For standard exception classes
using namespace std;
void testException(int num) {
if (num == 0) {
throw runtime_error("Runtime error: Number cannot be zero!");
}
if (num < 0) {
throw logic_error("Logic error: Negative number is not allowed!");
}
cout << "Number is: " << num << endl;
}
int main() {
try {
testException(0); // Throws runtime_error
}
catch (const runtime_error& e) {
cout << "Caught exception: " << e.what() << endl;
}
try {
testException(-1); // Throws logic_error
}
catch (const logic_error& e) {
cout << "Caught exception: " << e.what() << endl;
}
return 0;
}
Explanation:
testException() throws a runtime_error if the input is 0, and a logic_error if the input is a negative number.catch blocks are used to catch and handle the different types of exceptions (runtime_error and logic_error).Output:
Caught exception: Runtime error: Number cannot be zero!
Caught exception: Logic error: Negative number is not allowed!
You can have multiple catch blocks to handle different types of exceptions separately. C++ evaluates the catch blocks from top to bottom, and once a match is found, it executes that block and skips the rest.
#include <iostream>
#include <stdexcept>
using namespace std;
void testExceptions(int num) {
if (num == 0) {
throw runtime_error("Runtime error: Number cannot be zero!");
}
else if (num < 0) {
throw logic_error("Logic error: Negative number is not allowed!");
}
else if (num > 100) {
throw overflow_error("Overflow error: Number is too large!");
}
cout << "Valid number: " << num << endl;
}
int main() {
try {
testExceptions(0); // Throws runtime_error
}
catch (const runtime_error& e) {
cout << "Caught: " << e.what() << endl;
}
try {
testExceptions(-5); // Throws logic_error
}
catch (const logic_error& e) {
cout << "Caught: " << e.what() << endl;
}
try {
testExceptions(150); // Throws overflow_error
}
catch (const overflow_error& e) {
cout << "Caught: " << e.what() << endl;
}
return 0;
}
Output:
Caught: Runtime error: Number cannot be zero!
Caught: Logic error: Negative number is not allowed!
Caught: Overflow error: Number is too large!
catch(...))The catch(...) block is used to catch any type of exception that doesn't match the specific exception types provided in the preceding catch blocks. It is useful for handling unknown or unexpected exceptions.
#include <iostream>
using namespace std;
void testException() {
throw 42; // Throwing an integer
}
int main() {
try {
testException(); // Calling function that throws an exception
}
catch (int e) { // Catching integer exceptions
cout << "Caught an integer exception: " << e << endl;
}
catch (...) { // Catching any other exception
cout << "Caught an unknown exception!" << endl;
}
return 0;
}
Explanation:
throw 42; statement throws an integer exception.catch(int e) block handles the integer exception.catch(...) block catches any other exceptions (if the type doesn't match the specified one).Output:
Caught an integer exception: 42
Sometimes, you may want to catch an exception, process it, and then re-throw it to be handled by another part of the program. This can be done using the throw keyword inside a catch block.
#include <iostream>
using namespace std;
void funcA() {
try {
throw "Error in funcA"; // Throwing an exception in funcA
}
catch (const char* msg) {
cout << "Caught in funcA: " << msg << endl;
throw; // Re-throwing the caught exception
}
}
int main() {
try {
funcA(); // Call function which throws and re-throws an exception
}
catch (const char* msg) {
cout << "Caught in main: " << msg << endl;
}
return 0;
}
Explanation:
funcA(), caught within funcA(), and then re-thrown to be caught in the main() function.Output:
Caught in funcA: Error in funcA
Caught in main: Error in funcA
Exception handling in C++ provides a robust mechanism to deal with errors and exceptions that may occur during runtime. The key elements are:
try block: To define a section of code that might throw exceptions.throw keyword: Used to throw an exception.catch block: To handle specific types of exceptions.std::runtime_error, std::logic_error, and std::overflow_error.Exception handling provides a structured and clean way to handle errors, making your programs more resilient and maintainable.
Open this section to load past papers