Language Elements

Object Oriented Concepts

Data Types

Key Words

Arrays

Pointers

Data Structures

Multithreading

Errors and Exception Handling

Interview Questions



Exceptions and Error Handling in C++

An exception in C++ is an event that occurs during the execution of a program that disrupts the normal flow of instructions. It usually signals an error or an unexpected situation — such as division by zero, invalid memory access, or failure to open a file.

Exception handling provides a structured way to detect and respond to these events, separating error-handling code from regular logic. This improves clarity, maintainability, and safety in programs.

How Exceptions Work

When an exception is thrown:

  • The normal execution of the program stops immediately.
  • Control is transferred to the nearest matching catch block.
  • If no matching handler is found, the program terminates by calling std::terminate().

Basic Syntax

try {
    // Code that might throw an exception
    throw std::runtime_error("Something went wrong");
}
catch (const std::runtime_error &e) {
    std::cout << "Caught error: " << e.what() << std::endl;
}

Key Components

  • throw — Used to signal an exception.
  • try — Wraps code that might throw an exception.
  • catch — Handles the exception and defines recovery steps.

Types of Exceptions

  • Standard Exceptions: Defined in <stdexcept> and <exception> Examples: std::runtime_error, std::out_of_range, std::bad_alloc
  • User-defined Exceptions: Custom exception classes created for specific application needs.
  • System Exceptions: Rare OS-level issues, often unrecoverable within C++.

Catching Multiple Exceptions

try {
    // risky operations
}
catch (const std::invalid_argument &e) {
    std::cout << "Invalid argument: " << e.what();
}
catch (const std::out_of_range &e) {
    std::cout << "Out of range: " << e.what();
}
catch (...) {
    std::cout << "Unknown exception caught.";
}

Exception Safety in C++

When writing exception-safe code, C++ developers aim for:

  • No-throw guarantee: The function will never throw exceptions.
  • Strong guarantee: Operations are either completed successfully or have no effect.
  • Basic guarantee: Even if an exception occurs, resources are not leaked.
RAII (Resource Acquisition Is Initialization) and smart pointers help manage resources safely.

Nested try-catch Blocks

Nested handling allows different scopes to handle different exceptions:

try {
    try {
        throw std::logic_error("Inner error");
    }
    catch (const std::logic_error &e) {
        std::cout << "Handled inner logic error\n";
        throw; // rethrow to outer block
    }
}
catch (const std::exception &e) {
    std::cout << "Outer handler: " << e.what();
}

Best Practices

  • Throw exceptions only for exceptional situations — not for normal control flow.
  • Catch exceptions by const reference to avoid slicing and unnecessary copies.
  • Prefer specific exception types over catch(...) to improve clarity.
  • Use noexcept for functions guaranteed not to throw exceptions.

When Exceptions Should Not Be Used

  • Performance-critical loops where the overhead is too high.
  • Very low-level code (e.g., embedded systems) where exception support may be disabled.
  • When simple error codes are sufficient and clearer for the task.

Final Example

#include <iostream>
#include <stdexcept>

double divide(double a, double b) {
    if (b == 0) {
        throw std::invalid_argument("Division by zero");
    }
    return a / b;
}

int main() {
    try {
        std::cout << divide(10, 0);
    }
    catch (const std::invalid_argument &e) {
        std::cerr << "Error: " << e.what() << std::endl;
    }
}



Copyright © by Zafar Yasin. All rights reserved.