An error is an unforeseen circumstance that happens while a program is running, disrupting the regular sequence of operations. There are two categories of errors: validated and unvalidated errors. Validated errors are scrutinized by the compiler before runtime, making them compile-time errors. On the contrary, unvalidated errors are not inspected by the compiler.
In C++, the absence of checked exceptions, unlike in languages like Java, means that exceptions are unchecked. This allows any function to throw exceptions without the need to specify them in advance. Handling exceptions in C++ requires the programmer to employ the try, catch, and throw keywords, where the try block is used to identify and throw the object type causing the exception.
Why are exceptions not checked by the CPP compiler?
C++ is an expanded iteration of the C programming language; however, C lacks support for exceptions. Therefore, integrating exceptions into a C program can disrupt its functionality.
Inspecting exceptions during compilation will prompt the compiler to evaluate the flow diagrams, leading to heightened computational requirements and runtime. This additional load is irrelevant for applications that prioritize performance efficiency.
C++ provides developers with the freedom to determine the timing and location for managing exceptions. This level of flexibility enables C++ to defer exception handling until the compilation stage.
Example 1:
Let's consider an example to demonstrate how to manage checked exceptions.
#include <iostream>
using namespace std;
int division(int a, int b){
if (b == 0)
{
throw "Division by zero is not applicable";
}
return int(a / b);
}
int main()
{
int a = 0;
int b = 0;
cout << "Enter the number Numerator " << endl;
cin >> a;
cout << "Enter the Denominator " << endl;
cin >> b;
int result = 0;
try{
result = division(a, b);
cout << "Output: " << result << endl;
}catch (const char *msg)
{
cout << msg << endl;
}
return 0;
}
Output:
Explanation:
The variables utilized in the program are denoted as a and b. These represent the numerator and denominator values, respectively, which are input by the user.
The program consists of two functions: division and main. Within the division function, there are two parameters, a and b. This function returns an integer value, representing the result of dividing a by b. The program implements error handling utilizing the try, catch, and throw keywords. The try block encapsulates the code that could potentially generate an error, while the catch block handles the error message. When an error needs to be raised, the throw keyword is employed.
Example 2:
Let's consider another instance to demonstrate the proper approach in managing checked exceptions.
#include <iostream>
#include <stdexcept>
using namespace std;
class InsufficientFundsException: public exception {
public:
const char* what() const noexcept override {
return "Insufficient funds in the account.";
}
};
class BankAccount {
private:
double balance;
public:
BankAccount() : balance(0) {}
void deposit(double amount) {
if (amount < 0) {
throw invalid_argument("Invalid deposit amount.");
}
balance += amount;
cout << "Deposited: $" << amount << endl;
}
void withdraw(double amount) {
if (amount < 0) {
throw invalid_argument("Invalid withdrawal amount.");
}
if (amount > balance) {
throw InsufficientFundsException();
}
balance -= amount;
cout << "Withdrawn: $" << amount << endl;
}
void transfer(double amount, BankAccount& recipient) {
try {
withdraw(amount);
recipient.deposit(amount);
cout << "Transferred: $" << amount << endl;
} catch (const InsufficientFundsException& e) {
cerr << "Transfer failed: " << e.what() << endl;
} catch (const exception& e) {
cerr << "Transfer failed: " << e.what() << endl;
}
}
double getBalance() const {
return balance;
}
};
int main() {
BankAccount account1, account2;
try {
account1.deposit(1000);
account1.transfer(500, account2);
account1.withdraw(800);
account2.withdraw(2000);
} catch (const exception& e) {
cerr << "Error: " << e.what() << endl;
}
cout << "Account 1 Balance: $" << account1.getBalance() << endl;
cout << "Account 2 Balance: $" << account2.getBalance() << endl;
return 0;
}
Output:
Explanation:
In this illustration, the software includes various functions such as the BankAccount constructor, deposit, withdraw, transfer, and getBalance methods.
The deposit function accepts an amount as a parameter and validates if the amount is not negative. If the amount is negative, it will raise an invalid_argument exception; otherwise, it will add the deposited amount to the current balance.
The withdraw method accepts an amount as a parameter. If the amount is negative, it will raise an invalid_argument exception. Otherwise, it will deduct the specified amount from the balance. If the withdrawal amount surpasses the available balance, it will throw an insufficientFundsException error.
The transfer method accepts an amount and a reference to a different BankAccount object as parameters. It attempts to withdraw the specified amount from the current account and, upon success, deposits the amount into the recipient's account. In the event of catching an InsufficientFundsException during the withdrawal process, it manages the exception by displaying an error message. Finally, it outputs a message to signify the completion of the transfer process.
Error handling concept:
- In the transfer function , a try block attempts the withdrawal and transfer operation.
- If an InsufficientFundsException is caught during the withdrawal, it is handled in the catch block, where an error message is printed.
- In the main function , similar try-catch blocks are used to catch any exceptions that might be thrown during the operations.
Conclusion:
In summary, C++ provides robust exception-handling capabilities with the try, catch, and throw keywords, empowering developers to gracefully handle unexpected occurrences. In contrast to Java, C++ does not impose checked exceptions, giving programmers the flexibility to address exceptions according to their specific needs. By utilizing try-catch constructs, C++ programmers can protect their code from runtime errors and effectively manage the program's execution flow. The illustrations illustrate the process of throwing, catching, and managing exceptions, enhancing the dependability and resilience of C++ applications when faced with exceptional circumstances. Proficiency in implementing and understanding exception-handling concepts is essential for developing reliable and user-centric software in C++.