try
block.try
Block:
try
block.catch
block is skipped.throw
Statement:
try
block, use the throw
statement to signal the exception.throw
statement can throw any exception, including objects derived from the std::exception
class (the base class for most standard exceptions).catch
Block:
catch
blocks follow the try
block.catch
block attempts to handle a specific type of exception.catch
block’s parameter is usually a reference to the exception object that was thrown. You can use this object to access information about the error.try {
// Code that may throw an exception
throw exception; // This line will throw an exception
}
catch (ExceptionType1 e1) {
// Code to handle ExceptionType1
}
catch (ExceptionType2 e2) {
// Code to handle ExceptionType2
}
catch (...) {
// Code to handle any type of exception
}
#include <iostream>
#include <stdexcept> // For standard exceptions
int main()
{
int numerator ;
int denominator;
std::cout<< "Enter value for numerator \t";
std::cin>>numerator;
std::cout<< "Enter value for denominator \t";
std::cin>>denominator;
try
{
if (denominator == 0)
{
throw std::runtime_error("Division by zero error");
}
int result = numerator / denominator; // This will now never be reached if denominator is 0
std::cout << "Result: " << result << std::endl;
}
catch (const std::runtime_error &e)
{
std::cerr << "Error: " << e.what() << std::endl; // Access error message
}
catch (const std::exception &e)
{
std::cerr << "Unexpected error: " << e.what() << std::endl; // Catch any other std::exception
}
std::cout << "Program continues... after the try catch block" << std::endl;
return 0;
}
<stdexcept>
is included for using standard exceptions like std::runtime_error
.std::runtime_error
.catch
blocks to handle specific exceptions. Here, std::runtime_error
is caught separately from other std::exception
s.Exception handling in C++ is a mechanism that allows the program to manage errors and other exceptional events in a structured and controlled manner. Here are the key concepts and syntax related to exception handling in C++:
catch (const std::runtime_error& e) { /*...*/ }
Use Specific Exceptions: Catch specific exceptions before more general ones to ensure that specific errors are handled appropriately.
try
block.
catch (const std::exception& e) {
// Handle partially
throw; // Re-throw the same exception
}
noexcept
specifier is used instead of the old exception specifications.
void myFunction() noexcept {
// This function is guaranteed not to throw any exceptions
}
By following these guidelines and understanding the basics, you can effectively handle exceptions in C++ and write robust and maintainable code.
When creating a class in C++, exception handling code is typically included in several key areas to ensure robustness and proper error handling. These areas include constructors, member functions, and sometimes destructors. Let’s discuss each of these in detail:
Constructors are critical because they initialize the object. If a constructor fails, it should throw an exception to indicate that the object could not be properly created. Exception handling in constructors ensures that resources are properly managed, and partially constructed objects are not left in an invalid state.
#include <iostream>
#include <stdexcept>
class MyClass {
public:
MyClass(int value) {
if (value <= 0) {
throw std::invalid_argument("Value must be positive");
}
this->value = value;
}
private:
int value;
};
int main() {
try {
MyClass obj(-1); // This will throw an exception
} catch (const std::invalid_argument& e) {
std::cerr << "Caught an exception in constructor: " << e.what() << std::endl;
}
return 0;
}
Member functions often include exception handling to deal with invalid inputs, resource management issues, or other runtime errors. This ensures that the class can handle unexpected situations gracefully.
class MyClass {
public:
void setValue(int value) {
if (value <= 0) {
throw std::invalid_argument("Value must be positive");
}
this->value = value;
}
private:
int value;
};
int main() {
MyClass obj(10);
try {
obj.setValue(-5); // This will throw an exception
} catch (const std::invalid_argument& e) {
std::cerr << "Caught an exception in member function: " << e.what() << std::endl;
}
return 0;
}
Destructors should generally avoid throwing exceptions because they are called during stack unwinding when another exception is already in progress, which can lead to std::terminate
being called. However, destructors can use exception handling to catch exceptions and log errors or clean up resources safely.
class MyClass {
public:
~MyClass() {
try {
// Cleanup code that might throw an exception
} catch (...) {
// Log the error, but do not rethrow
std::cerr << "Exception caught in destructor" << std::endl;
}
}
};
In classes managing resources such as dynamic memory, file handles, or network connections, exception handling is crucial to ensure resources are released properly. This is often done using the RAII (Resource Acquisition Is Initialization) idiom, where resources are acquired in the constructor and released in the destructor.
#include <fstream>
#include <iostream>
class FileHandler {
public:
FileHandler(const std::string& filename) {
file.open(filename);
if (!file.is_open()) {
throw std::runtime_error("Failed to open file");
}
}
~FileHandler() {
if (file.is_open()) {
file.close();
}
}
private:
std::fstream file;
};
int main() {
try {
FileHandler fh("nonexistentfile.txt");
} catch (const std::runtime_error& e) {
std::cerr << "Caught an exception: " << e.what() << std::endl;
}
return 0;
}
By incorporating exception handling into these key areas, you ensure that your class is robust, resilient to errors, and maintains a consistent state even when exceptions occur.