Week 14 - Exception Handling

Download as docx, pdf, or txt
Download as docx, pdf, or txt
You are on page 1of 14

Exception Handling

Definition: An exception is a response to an exceptional circumstance that arises while a program is running, such as an attempt to divide by zero.
Exceptions provide a way to transfer control from one part of a program to another. When an exceptional circumstance arises within a block of code, an
exception is thrown that transfers the control to the exception handler. If no exception is thrown, the code continues normally and all handlers are
ignored.
Structure
try
{
// Block of code to try
throw exception;
}
catch ()
{
// Block of code to handle errors
}
Example
#include <iostream>
#include <stdexcept>
using namespace std;

int main()
{
try
{
throw runtime_error("This is an error message.");
}
catch (const runtime_error& e)
{
cerr << "Caught an exception: " << e.what() << std::endl;
}
}
Try block: The code which can throw any exception is kept inside (or enclosed in) a try block. Then, when the code will lead to any error, that
error/exception will get caught inside the catch block.
Catch block: catch block is intended to catch the error and handle the exception condition. We can have multiple catch blocks to handle different types
of exception and perform different actions when the exceptions occur. For example, we can display descriptive messages to explain why any particular
exception occurred.
Throw statement: It is used to throw exceptions to exception handler i.e., it is used to communicate information about error. A throw expression
accepts one parameter and that parameter is passed to handler. throw statement is used when we explicitly want an exception to occur, then we can use
throw statement to throw or generate that exception.

Below program compiles successfully but We can handle such situations using exception handling and can inform the user that you cannot divide
the program fails at runtime, because of a number by zero, by displaying a message.
division by zero.
int main() int main() catch (int num_exception) // int is caught
{ { {
double numerator, denominator, double numerator, denominator, divide; cout << "Cannot divide by " << num_exception <<
divide; numerator = 10; endl;
numerator = 10; denominator = 0; }
denominator = 0; }
try
divide = numerator / denominator; {
// will generate run time error. if (denominator == 0)
} throw 0; \\int is thrown

divide = numerator / denominator;


// will generate runtime error here,
//but the program will not be disturbed
//and continue working
}
Need for exceptional Handling
In the case of checking if a number is zero before division, using an if-else statement is indeed simple and works fine. However, consider a more
complex program where division operations are performed in multiple places. If you forget to check for zero at just one place, it could cause a program
crash. By using exceptions, you can ensure that such errors are caught and handled appropriately, making your program more robust and reliable.

Exception handling is a powerful tool in programming languages like C++, and it provides several advantages over traditional error-handling methods
such as if-else statements or switch cases. Here are some reasons why exception handling is important:
1. Separation of Error Handling Code from Regular Code: Exception handling allows you to separate the code that handles errors from the code
that performs the normal functionality of your program. This makes your code cleaner, easier to read, and maintain.
2. Propagating Errors Up the Call Stack: If an error occurs deep within a series of nested function calls, propagating that error up to the function that
can handle it would require each intermediate function to have error handling code. With exceptions, the error automatically propagates up the call
stack until it is caught.
3. Handling of Unexpected Errors: While if-else or switch-case statements can handle known errors, exceptions are designed to handle unexpected or
unforeseen errors. For example, if you’re reading data from a file or a network, an error could occur that you didn’t anticipate (like the file being
deleted while you’re reading it, or the network connection dropping). Exceptions allow your program to catch these errors and handle them
gracefully.
4. Constructor Failures: In C++, constructors do not have a return value. So, if an error occurs during object construction, you cannot use a return
value to indicate the error. In this case, throwing an exception is the best way to signal that something went wrong.
5. Grouping of Error Types: With exceptions, you can create a hierarchy of exception classes, allowing similar types of errors to be caught and
handled in the same way. This is not possible with traditional error-handling techniques.
6. Resource Management: When an exception is thrown, the C++ runtime system takes care of unwinding the stack, which means it automatically
releases the resources (like memory or file handles) that were acquired by the function that threw the exception. This helps prevent resource leaks in
your program.
Data type of catch block
In C++, the data type of the variable in the catch block depends on the type of exception that is being thrown. The catch block can handle exceptions of
any type. You can throw any literal, variable, or class, depending on the situation and what you want to execute inside the catch block1. The catch
parameter takes the value passed by the throw statement.
In this code, the class nameless object us passed to catch block.
class SimpleException int main()
{ {
public: try
string message; {
SimpleException(string msg): message(msg) {} SimpleException::checkNumber(5);
SimpleException::checkNumber(15);
static void checkNumber(int number) }
{ catch(SimpleException& e)
if (number > 10) {
{ cout << "Caught an exception: " << e.message << endl;
throw SimpleException("Number is greater than 10"); }
}
cout << "Number is " << number << endl; return 0;
} }
};
Data type if catch block and multiple catch stamens
#include <iostream> Output:
#include <string> Caught an integer exception: -1
using namespace std;

int main()
{ The reason you’re only seeing the output
int number = -1; “Caught an integer exception: -1”
string str = ""; is because an exception causes the program to exit the try
block immediately. As soon as the integer exception is thrown,
try
{ the program jumps to the catch block that handles integer
if (number < 0) exceptions and the rest of the code in the try block is not
{ executed.
throw number; // This will throw an integer exception
}
if (str.empty())
{
throw str; // This will throw a string exception
}
}
catch (int e)
{
cout << "Caught an integer exception: " << e << endl;
}
catch (string e)
{
cout << "Caught a string exception: " << e << endl;
}
catch (...)
{
cout << "Caught an unknown exception" << endl;
}
}
catch (...)
The catch (...) block in C++ is a special catch block known as a catch-all handler. It is used to catch all exceptions that are not already caught by
previous catch blocks.
Here’s how it works:
 When an exception is thrown, the program starts looking for a catch block that can handle the exception.
 It first looks for a catch block that matches the exact type of the exception.
 If it doesn’t find one, it looks for a catch block that can handle a parent class of the exception.
 If it still doesn’t find one, it looks for a catch-all handler (catch (...)).
 If it finds a catch-all handler, the handler catches the exception, regardless of its type.
 The catch-all handler is typically used as a last resort to catch any exceptions that were not anticipated and handled by specific catch blocks. It
ensures that no exceptions go unhandled, which could otherwise cause the program to terminate abruptly.

Example of catch(…)
int main() In C++, when you use a catch-all block like catch (...), it means that this
{ block will catch any exception, regardless of its type. However, because
try the type of the exception is not specified in the catch block, you don’t
{ have a specific exception object that you can work with inside the catch
throw "An error occurred"; // Throw a const char* exception block.
}
catch (int e) This means that you can’t call any methods on the exception object,
{ because there’s no named exception object available. For example, you
cout << "Caught an integer exception: " << e << endl; can’t call the what() method to get a description of the exception, because
} you don’t have a specific exception object to call what() on.
catch (...)
{
cout << "Caught an unknown exception" << endl;
}
}
<stdexcept>
The #include <stdexcept> directive in C++ includes the <stdexcept> header file in your program. This header file is part of the C++ Standard Library
and it defines several types of exception classes that you can use in your program.
The C++ Standard Library provides several types of exception classes that you can use in your program. Here are some of them:

 std::exception: The base class for all standard exceptions.


 std::logic_error: An exception that theoretically can be detected by reading the code. Examples are domain errors, out-of-range errors, etc.
 std::runtime_error: An exception that theoretically cannot be detected by reading the code. Most exceptions derived from this class are thrown
either by the operating system or the runtime library.
 std::invalid_argument: Reports an invalid argument.
 std::length_error: Exception thrown to report length errors3.

Few examples
exception logic_error runtime_error
try try try
{ { {
int number = -1; int number = 101; int* ptr = nullptr;
if (number < 0) if (number > 100) if (ptr == nullptr)
{ { {
throw exception(); throw logic_error("Number is greater than 100"); throw runtime_error("Null pointer error");
} } }
} } }
catch (exception& e) catch (logic_error& e) catch (std::runtime_error& e)
{ { {
cout << "Caught a standard exception"; cout << "Logic error: " << e.what(); cout << "Rruntime error: " << e.what();
} } }
catch (std:exception& e) can catch all exceptions that are derived from the std::exception class, which includes std::runtime_error, std::logic_error,
std::length_error, and many others.

Other Exceptions
int main() Output:
{ bad_alloc exception: can't allocate memory.
const unsigned long SIZE = 999999999999;
char* ptr; No, std::bad_alloc is not part of the <stdexcept> header. It is part of the
try new header in C++.
{
ptr = new char[SIZE]; //allocate SIZE bytes std::bad_alloc is part of <new> header.
}
catch(bad_alloc) However, bad_alloc can still be used without specifying the <new>
{ header.
cout << "bad_alloc exception: can't allocate memory. " << endl;
return(1);
New will throw an exception if it fails to allocate memory.
}

delete[] ptr;

cout << "Memory use is successful. " << endl;


}
Example of Stack (single catch)
#include <iostream> int pop()
using namespace std; {
const int MAX = 3; if(top < 0)
{
class Stack throw Range(); //if stack empty, //throw exception
{ }
private:
int st[MAX]; //array of integers return st[top--]; //take number off stack
int top; //index of top of stack }
};
public:
class Range //exception class for Stack int main()
{ {
//note: empty class body Stack s1;
}; try
{
Stack() //constructor s1.push(11);
{ s1.push(22);
top = -1; s1.push(33);

} cout << “1: “ << s1.pop() << endl;


cout << “2: “ << s1.pop() << endl;
void push(int var) cout << “3: “ << s1.pop() << endl;
{ }
if(top >= MAX-1)
{ catch(Stack& st) //exception handler // object can be declared
//if stack full, //throw exception {
throw Range(); cout << "Exception: Stack Full or Empty" << endl;
} }
}
st[++top] = var; //put number on stack
}
Example of Stack (Multiple catch)
#include <iostream> int main()
using namespace std; {
const int MAX = 3; Stack s1;
try
class Stack {
{ s1.push(11);
private: s1.push(22);
int st[MAX]; int top; s1.push(33);

public: cout << "1: " << s1.pop() << endl;


class Full { }; class Empty { }; cout << "2: " << s1.pop() << endl;
cout << "3: " << s1.pop() << endl;
Stack() cout << "4: " << s1.pop() << endl;
{ top = -1; } }

void push(int var) catch(Stack::Full) // instead of objects, :: can be used


{ {
if(top >= MAX-1) cout << "Exception: Stack Full" << endl;
{ }
throw Full(); catch(Empty& em)
} {
st[++top] = var; cout << "Exception: Stack Empty" << endl;
} }

int pop() }
{
if(top < 0)
{
throw Empty();
}
return st[top--];
}
};
Exceptions with Arguments, and nested classes
class Distance Distance(int ft, float in)
{ {
private: if(in >= 12.0)
int feet; {
float inches; throw InchesEx("2-arg constructor", in);
}
public:
class InchesEx // nested class//keep this class and its attributes public feet = ft;
{ inches = in;
public: }
string origin;
float iValue; void getdist()
{
InchesEx(string s, float in) cout << endl <<"Enter feet: "; cin >> feet;
{ cout << "Enter inches: "; cin >> inches;
origin = s;
iValue = in; if(inches >= 12.0)
} {
}; throw InchesEx("getdist() function", inches);
}
Distance() }
{
feet = 0; void showdist()
inches = 0.0; {
} cout << feet << "'-" << inches << '"';
}
};

int main()
{
try
{
Distance dist1(17, 3.5);
Distance dist2;

dist2.getdist();
cout << endl << "dist1 = "; dist1.showdist();
cout << endl << "dist2 = "; dist2.showdist();
}

catch(Distance::InchesEx ix)
{
cout << "\nInitialization error in " << ix.origin
<< ".\n Inches value of " << ix.iValue
<< " is too large.";
}
cout << endl;
}
Exception Handling Home/Lab work
Question 1
Create a student grading system using C++..
1. Create a Student class that includes data members for the student’s name and an array of marks for 5 subjects.
2. The class should have a static member function validateMark that takes a mark as an argument. This function should throw an
exception if the mark is less than 0 or more than 100.
3. The class should also have a method addMark that takes one mark at a time. This method should call
the validateMark function to validate the mark before adding it to the marks array. If the marks array is already full,
the addMark method should throw an exception.
4. Write a main function that creates Student object and attempts to add marks. The main function should
include try and catch blocks to handle any exceptions that are thrown. If an exception is thrown, it should print an error
message. If no exception is thrown, it should print the marks of the students.
Note: a single “out_of_range” exception can be thrown. Which is the part of <stdexcept>.

Question 2 (same concept as Exceptions with Arguments, and nested classes)


Design a Course class in C++ that includes data members for the course name and the maximum number of students that can
enroll in the course. The class should have a method to enroll a student in the course. This method should throw an exception if the
course is already full. Implement the exception handling using a nested class within the Course class. Demonstrate the usage of
this class and its exception handling in a main function.

Question 3 (Example of Stack Multiple catch)


Design a BankAccount class in C++ that includes data members for the account balance. The class should have methods to
deposit and withdraw money. These methods should throw exceptions if a withdrawal would result in a negative balance or if a
deposit or withdrawal is for a negative amount. Implement the exception handling using two empty nested classes within the
BankAccount class. Demonstrate the usage of this class and its exception handling in a main function.

You might also like