Exception Handling
Try-Catch Blocks
Handle runtime errors gracefully with try, catch, and exception propagation mechanics.
Interview: Fundamental comparison of error-handling styles (error codes vs. exceptions), catching by reference, and polymorphic catch behavior.
In C++, Exceptions provide a structured way to handle runtime anomalies (like out-of-memory or file-not-found) by separating the error-detection code from the error-handling logic.
Try Block
Encloses the code that might throw an exception. If an error occurs, execution of the try block stops immediately.
Catch Block
Inspects the thrown exception. Multiple catch blocks can follow a try block to handle different error types.
Polymorphic Catch
Always catch exceptions by const reference to avoid slicing and ensure polymorphic behavior.
Propagation and Slicing
When an exception is thrown, the runtime searches up the call stack for a matching catch block. If caught by value, the exception object is copied into the catch parameter, which causes Object Slicing if the object is a derived exception type.
Catch Order Requirement
Catch blocks are evaluated sequentially. You must place catch blocks for derived exception types before base exception types. A base class catch block (e.g. const std::exception&) will intercept derived exceptions, rendering more specific catch blocks dead code.
Code Walkthrough
Demonstrates safe usage of multiple catch blocks and hierarchical ordering.
#include <iostream> #include <stdexcept>void performDivision(int a, int b) { if (b == 0) { throw std::invalid_argument("Division by zero is undefined."); } std::cout << "Result: " << (a / b) << std::endl; }
int main() { try { performDivision(10, 0); } catch (const std::invalid_argument& e) { // More specific exception caught first std::cerr << "Specific argument error: " << e.what() << std::endl; } catch (const std::exception& e) { // Base exception caught second std::cerr << "Generic exception caught: " << e.what() << std::endl; } catch (...) { // Catch-all block for non-standard exceptions std::cerr << "Unknown object thrown!" << std::endl; } return 0; }
Interview-Relevant Information
Q: Why should you catch exceptions by const reference rather than by value?
Answer: Catching by value copies the exception object. If a derived exception is thrown and caught by a base type by value, the derived parts are sliced off, and dynamic polymorphism (calling e.what()) is lost. Catching by const reference avoids copying overhead and preserves the derived class identity and behavior.
Q: What is the purpose of the catch-all (...) block?
Answer: The catch-all block handles any exception that wasn't caught by preceding blocks, including types not deriving from std::exception (like raw integers or strings). It is typically placed at the end of the catch list to log errors or perform emergency cleanup before terminating or rethrowing.
Quick Checklist
Did you put derived catch blocks before base ones? Are you catching by const reference? If yes, your basic try-catch setup is correct.
Use Cases
Interpreting file-system or network connection timeouts and failures gracefully without crashing.
Validating input arguments within deep libraries and propagating anomalies back to the driver module.
Common Mistakes
Catching by value, resulting in object slicing and loss of type-specific details.
Placing base class exceptions like std::exception above derived ones, making specific catch blocks unreachable.