ScholarQuill logoScholarQuillUniversity Notes
  • Notes
  • Past Papers
  • Blogs
  • Todo
Login
ScholarQuill logoScholarQuillUniversity Notes
Login
NotesPast PapersBlogsTodo
More
SubjectsDiscussionCGPA CalculatorGPA CalculatorStudent PortalCourse Outline
About
About usPrivacy PolicyReportContact
Notes
Past Papers
Blogs
Todo
Analytics
    Current Subject
    🧩
    Object Oriented Programming
    CC-211
    Progress0 / 24 topics
    Topics
    1. Object-Oriented Design: History and Advantages2. Object-Oriented Programming: Terminology and Features3. Classes and Objects4. Data Encapsulation5. Constructors and Destructors6. Access Modifiers7. Const vs Non-Const Functions8. Static Data Members and Functions9. Function Overloading10. Operator Overloading11. Identification of Classes and Their Relationships12. Composition13. Aggregation14. Inheritance15. Multiple Inheritances16. Polymorphism17. Abstract Classes18. Interfaces19. Generic Programming Concepts20. Function Templates21. Class Templates22. Standard Template Library23. Object Streams: Data and Object Serialization24. Exception Handling
    CC-211›Exception Handling
    Object Oriented ProgrammingTopic 24 of 24

    Exception Handling

    8 minread
    1,287words
    Intermediatelevel

    Exception Handling in C++

    Exception handling is a mechanism to handle runtime errors, which may occur due to various reasons like invalid input, hardware failure, or other unexpected issues that can disrupt the normal flow of the program. C++ provides a robust mechanism for dealing with exceptions, which allows programmers to write code that can gracefully handle errors without crashing the program.

    In C++, exception handling is done using the try, throw, and catch keywords.

    Basic Terminology

    1. Exception: An object that represents an error condition. When an error occurs, an exception object is "thrown."
    2. Throw: The action of generating an exception. It signals the occurrence of an error.
    3. Catch: A block of code that handles an exception when it's thrown.
    4. Try: A block of code that might throw an exception.

    Syntax of Exception Handling

    try {
        // Code that might throw an exception
    } catch (exceptionType1& e) {
        // Handle exception of type exceptionType1
    } catch (exceptionType2& e) {
        // Handle exception of type exceptionType2
    } catch (...) {
        // Catch any exception (catch-all)
    }
    

    Key Concepts in Exception Handling

    1. try block: The code that might cause an exception is placed inside the try block.
    2. throw statement: If an error occurs, a throw statement is used to "throw" an exception. The type of the exception can be a built-in type (e.g., int, char) or a user-defined type (e.g., a class).
    3. catch block: After an exception is thrown, control is transferred to the appropriate catch block that handles the exception. The catch block is able to handle the specific exception type it is designed for.
    4. catch-all handler: If no catch block matches the thrown exception, the catch-all block catch(...) is used to handle any type of exception.

    Simple Example

    Let's look at a basic example of exception handling:

    #include <iostream>
    using namespace std;
    
    int divide(int a, int b) {
        if (b == 0) {
            throw "Division by zero error!";  // Throwing an exception
        }
        return a / b;
    }
    
    int main() {
        int num1 = 10, num2 = 0;
    
        try {
            int result = divide(num1, num2);  // Try to divide
            cout << "Result: " << result << endl;
        } catch (const char* msg) {
            cout << "Caught an exception: " << msg << endl;  // Catch the exception
        }
    
        return 0;
    }
    

    Explanation:

    • Throwing an Exception: Inside the divide() function, if b is zero, a string exception is thrown using throw "Division by zero error!".
    • Catching the Exception: In main(), the try block calls the divide() function. If an exception is thrown, the catch block catches it and prints the error message.

    Output:

    Caught an exception: Division by zero error!
    

    Exception Handling Flow

    1. The program enters the try block.
    2. If an exception is thrown inside the try block (e.g., due to a zero denominator), control is transferred to the appropriate catch block.
    3. The catch block executes and handles the exception.
    4. If no exception is thrown, the catch block is skipped, and the program continues after the try-catch blocks.

    Multiple Catch Blocks

    You can have multiple catch blocks to handle different types of exceptions:

    #include <iostream>
    using namespace std;
    
    void process(int num) {
        if (num == 0) {
            throw "Zero is not allowed!";  // Throw string exception
        }
        if (num < 0) {
            throw -1;  // Throw integer exception
        }
        cout << "Processing number: " << num << endl;
    }
    
    int main() {
        try {
            process(0);  // Throws string exception
        } catch (const char* msg) {
            cout << "Caught exception: " << msg << endl;
        } catch (int e) {
            cout << "Caught exception with code: " << e << endl;
        }
    
        return 0;
    }
    

    Output:

    Caught exception: Zero is not allowed!
    

    If we pass a negative number to process(), it would catch the integer exception.

    C++ Standard Library Exception Classes

    C++ provides a hierarchy of predefined exception classes in the Standard Library. These are defined under the std namespace and inherit from the base class std::exception.

    • std::exception: The base class for all exceptions in the C++ Standard Library.
    • std::logic_error: Represents errors in the logic of the program (e.g., invalid arguments).
      • Example: std::invalid_argument, std::out_of_range.
    • std::runtime_error: Represents errors that can occur during the execution of the program (e.g., resource failures).
      • Example: std::overflow_error, std::underflow_error.

    Example with Standard Library Exceptions

    #include <iostream>
    #include <stdexcept>
    using namespace std;
    
    void checkNumber(int num) {
        if (num < 0) {
            throw invalid_argument("Negative numbers are not allowed.");
        } else if (num == 0) {
            throw runtime_error("Zero is not a valid number.");
        }
    }
    
    int main() {
        try {
            checkNumber(-1);  // Will throw invalid_argument exception
        } catch (const invalid_argument& e) {
            cout << "Caught exception: " << e.what() << endl;
        } catch (const runtime_error& e) {
            cout << "Caught exception: " << e.what() << endl;
        }
    
        return 0;
    }
    

    Output:

    Caught exception: Negative numbers are not allowed.
    
    • e.what(): The what() function returns a description of the exception. This is a method defined in the std::exception class, which is inherited by all exceptions.

    Stack Unwinding

    When an exception is thrown, the C++ runtime performs stack unwinding, which involves:

    1. Destroying the local objects in the current stack frame of the try block.
    2. Passing control to the nearest matching catch block.
    3. If the exception is not caught, it propagates up the call stack to the calling functions, potentially terminating the program if uncaught.

    Custom Exceptions

    You can create custom exception classes by inheriting from std::exception and overriding the what() method:

    #include <iostream>
    #include <stdexcept>
    using namespace std;
    
    class MyException : public exception {
    public:
        const char* what() const noexcept override {
            return "This is a custom exception!";
        }
    };
    
    void triggerException() {
        throw MyException();  // Throw custom exception
    }
    
    int main() {
        try {
            triggerException();  // Calls function that throws exception
        } catch (const MyException& e) {
            cout << "Caught: " << e.what() << endl;
        }
    
        return 0;
    }
    

    Output:

    Caught: This is a custom exception!
    

    Best Practices for Exception Handling

    1. Use exceptions for exceptional conditions: Exceptions should not be used for regular control flow (e.g., loops, normal conditions).
    2. Catch exceptions by reference: Catch exceptions by reference to avoid slicing and to catch both base and derived exceptions.
      catch (const std::exception& e) { ... }
      
    3. Avoid catching exceptions that you cannot handle: Don't catch exceptions you don't know how to handle. Let them propagate up the call stack to a point where they can be meaningfully dealt with.
    4. Exception safety: Ensure that the program remains in a consistent state even when an exception occurs. Use techniques like RAII (Resource Acquisition Is Initialization) to manage resources (e.g., file handles, memory).
    5. Don't use exceptions for control flow: Avoid using exceptions for expected events like end-of-file or invalid user input. These are better handled with regular control structures.

    Conclusion

    Exception handling in C++ is a powerful mechanism to deal with errors in a controlled way, allowing you to separate error-handling logic from normal program flow. By using try, throw, and catch, you can catch exceptions and prevent program crashes. The C++ Standard Library provides built-in exception types, but you can also create your own custom exceptions. Proper exception handling improves program robustness and makes error handling more manageable.

    Previous topic 23
    Object Streams: Data and Object Serialization

    Past Papers

    Open this section to load past papers

    Click on Show Past Papers to see past papers.
    On This Page
      Reading Stats
      Est. reading time8 min
      Word count1,287
      Code examples0
      DifficultyIntermediate