LearnContact
Lesson 2810 min read

Exception Handling

When a program encounters an unexpected problem, it should respond safely instead of terminating unexpectedly. In this lesson, you will learn how C++ uses try, throw, and catch to detect and handle exceptional situations.

Introduction

In the previous lesson, you learned about namespaces. Now consider a program that asks the user to enter two numbers and performs a calculation.

Suppose the user enters 20 as the numerator and 0 as the denominator. The program attempts to perform integer division by zero, which is an invalid operation and results in undefined behavior.

Problematic Operation
int numerator = 20;
int denominator = 0;

int result =
    numerator / denominator;

Programs can also encounter many other exceptional situations, such as invalid input, unavailable files, failed network operations, or insufficient resources.

Unhandled Problem

  • An exceptional condition occurs.
  • The program does not respond properly.
  • The operation cannot continue normally.
  • The application may terminate unexpectedly.

Handled Exception

  • The exceptional condition is detected.
  • An exception is thrown.
  • A matching handler responds.
  • The program handles the situation safely.
Normal Program Execution
Exceptional Condition Detected
Throw Exception
Handle Exception
The Main Idea

Exception handling provides a structured way to transfer control from code that detects an exceptional condition to code designed to handle it.

What is Exception Handling?

Exception handling is a mechanism for reporting and handling exceptional situations that occur while a program is running.

Instead of mixing every possible error response directly into normal program logic, C++ allows code to throw an exception and transfer control to a matching handler.

Exception Handling Concept
Normal Code
    │
    ▼
Exceptional Condition
    │
    ▼
Throw Exception
    │
    ▼
Find Matching Handler
    │
    ▼
Handle Situation
ConceptMeaning
ExceptionAn object or value used to report an exceptional condition
ThrowSignals an exception
HandlerCode that catches and handles an exception
try BlockContains code associated with exception handlers
catch BlockHandles a matching exception
Simple Definition

Exception handling allows one part of a program to report an exceptional situation and another part to handle it.

Why Do We Need Exception Handling?

Real applications interact with users, files, networks, databases, memory, devices, and external systems. Many operations can fail for reasons that are not part of the normal successful path.

Without Structured Handling

  • Error checks may be scattered everywhere.
  • Normal logic becomes harder to read.
  • Failures may be ignored.
  • Unexpected termination becomes more likely.
  • Errors may be difficult to propagate.

With Exception Handling

  • Exceptional situations can be reported clearly.
  • Handlers can be separated from normal logic.
  • Errors can propagate to appropriate levels.
  • Different exception types can be handled differently.
  • Applications can respond more deliberately.

Controlled Error Handling

Exceptional situations can be handled by dedicated code.

Cleaner Normal Logic

The successful execution path can remain easier to follow.

Error Propagation

Exceptions can move through function calls until a suitable handler is found.

Type-Based Handling

Different exception types can have different handlers.

Better Diagnostics

Meaningful exception information can help explain failures.

Robust Applications

Programs can respond deliberately to recoverable and unrecoverable situations.

Real-World Analogy

Imagine using an ATM. You insert your card and enter a PIN.

If the PIN is correct, the ATM continues with the transaction. If the PIN is incorrect, the machine does not simply shut down. It detects the problem and follows an alternative error-handling path.

ATM Analogy
          ATM Transaction
                 │
                 ▼
             Enter PIN
                 │
         ┌───────┴───────┐
         ▼               ▼
      Correct         Incorrect
         │               │
         ▼               ▼
     Continue      Handle Problem
                         │
                         ▼
                Display Error Message
ATM ProcessException Handling
Transaction operationProgram operation
Check PINExecute potentially failing code
Invalid PIN detectedExceptional condition detected
Report the problemThrow an exception
Display error responseCatch and handle the exception
Perform Operation
Detect Problem
Report Exceptional Condition
Execute Handler
Alternative Control Path

Exception handling provides a separate path for exceptional situations instead of treating them as part of the normal successful flow.

Exception Handling Keywords

C++ exception handling commonly uses three keywords: try, throw, and catch.

1️⃣ try

Introduces a block of code associated with one or more exception handlers.

2️⃣ throw

Signals an exception and provides the exception object or value.

3️⃣ catch

Defines a handler for a matching exception type.

General Syntax
try
{
    // Code that may throw
}
catch (ExceptionType value)
{
    // Handle matching exception
}
Throwing an Exception
throw 100;
KeywordPurpose
tryAssociates a block with exception handlers
throwSignals an exception
catchHandles a matching exception
Three-Part Process

Code executes in a try block, an exceptional condition can cause an exception to be thrown, and a matching catch handler processes it.

Exception Handling Flow

When code inside a try block throws an exception, normal execution of that try block stops. C++ searches for a matching handler.

Enter try Block
Execute Statements
Exception Thrown?
Find Matching catch
Execute Handler
Detailed Flow
Program Starts
      │
      ▼
Enter try Block
      │
      ▼
Execute Code
      │
      ▼
Exception Thrown?
   ┌──┴──┐
   │     │
  No    Yes
   │     │
   ▼     ▼
Continue  Stop Remaining try Code
             │
             ▼
       Search for Handler
             │
             ▼
       Matching catch Found
             │
             ▼
        Execute Handler
SituationResult
No exception is thrownThe try block continues normally
An exception is thrownRemaining statements in the try block are skipped
Matching handler existsThe matching catch block executes
No matching handler existsThe exception continues searching outward; if ultimately unhandled, the program terminates
Execution After throw

Once an exception is thrown, the remaining statements in that try block are not executed unless control later returns through some separate program path.

Example 1: Basic Exception Handling

The following program throws an integer value and handles it with a matching catch block.

Example 1: Basic Exception Handling
#include <iostream>

int main()
{
    try
    {
        throw 100;
    }
    catch (int number)
    {
        std::cout
            << "Exception: "
            << number;
    }

    return 0;
}

How the Program Works

  • Execution enters the try block.
  • throw 100 creates an exception of type int.
  • The remaining execution of the try block stops.
  • C++ searches for a matching handler.
  • catch (int number) matches the thrown int.
  • The handler receives the value 100.
  • The exception information is displayed.
Exception Transfer
throw 100
    │
    ▼
Exception Type: int
    │
    ▼
catch (int number)
    │
    ▼
number = 100
Output
Exception: 100
Type Matching

The catch handler is selected because its parameter type matches the type of the thrown exception.

Example 2: Division by Zero

For integer arithmetic, division by zero is invalid and results in undefined behavior. The program can check the denominator before performing the division and throw an exception when the operation is invalid.

Example 2: Division by Zero
#include <iostream>

int main()
{
    int numerator = 20;
    int denominator = 0;

    try
    {
        if (denominator == 0)
        {
            throw "Division by zero error!";
        }

        std::cout
            << numerator / denominator;
    }
    catch (const char* message)
    {
        std::cout << message;
    }

    return 0;
}

How the Program Works

  • The denominator contains 0.
  • The condition denominator == 0 becomes true.
  • A string literal is thrown.
  • The division statement is skipped.
  • catch (const char* message) handles the exception.
  • The error message is displayed.
Division Check Flow
denominator = 0
       │
       ▼
denominator == 0?
       │
      Yes
       │
       ▼
Throw Message
       │
       ▼
Catch const char*
       │
       ▼
Display Error
Output
Division by zero error!
Important Distinction

C++ does not automatically convert every programming error into a catchable exception. In this example, the program explicitly checks the denominator and throws an exception before attempting invalid integer division.

Example 3: Multiple Catch Blocks

A try block can be followed by multiple catch handlers. This allows different exception types to be handled differently.

Example 3: Multiple Catch Blocks
#include <iostream>

int main()
{
    try
    {
        throw 25.5;
    }
    catch (int number)
    {
        std::cout
            << "Integer Exception";
    }
    catch (double number)
    {
        std::cout
            << "Double Exception";
    }

    return 0;
}
Handler Selection
throw 25.5
     │
     ▼
Type: double
     │
     ▼
catch (int)
     │
  No Match
     │
     ▼
catch (double)
     │
   Match
     │
     ▼
Execute Handler
Thrown TypeHandlerMatches?
doublecatch (int)No
doublecatch (double)Yes
Output
Double Exception
Only One Matching Handler Executes

After an exception is thrown, C++ selects a matching handler. Once that handler executes, later handlers associated with the same try block are not also executed.

Catch-All Handler

A catch-all handler uses catch (...) and can handle exceptions that were not matched by earlier handlers associated with the same try block.

Catch-All Syntax
catch (...)
{
    std::cout
        << "Unknown exception occurred!";
}
Specific Handlers Before Catch-All
try
{
    // Code that may throw
}
catch (int value)
{
    // Handle int
}
catch (double value)
{
    // Handle double
}
catch (...)
{
    // Handle anything else
}
Exception Thrown
Check Specific Handlers
No Specific Match
Execute catch (...)

Catch-All First

  • General handler appears before specific handlers.
  • It would handle exceptions before later handlers.
  • Specific handling becomes unavailable.
  • The ordering is incorrect.

Catch-All Last

  • Specific handlers are checked first.
  • Known exception types receive specific handling.
  • Unknown types fall back to catch (...).
  • The handler order is clear.
Place catch (...) Last

A catch-all handler must appear after the specific handlers associated with the same try block.

Program Execution Flow

The complete exception-handling flow depends on whether an exception is thrown and whether a matching handler can be found.

Program Starts
Enter try Block
Execute Code
Throw if Necessary
Find Matching Handler
Continue After Handling
Complete Execution Flow
Program Starts
      │
      ▼
Enter try Block
      │
      ▼
Execute Statements
      │
      ▼
Exception Thrown?
   ┌──┴──┐
   │     │
  No    Yes
   │     │
   ▼     ▼
Finish   Stop Remaining
try      try Statements
   │         │
   │         ▼
   │    Search for Handler
   │         │
   │         ▼
   │    Matching catch
   │         │
   │         ▼
   │    Execute Handler
   │         │
   └────┬────┘
        ▼
Continue After
Handler Sequence
StepWhat Happens
1The program enters the try block
2Statements execute normally
3An exceptional condition may cause a throw
4The remaining try statements are skipped
5A matching handler is selected
6The catch block executes
7Execution continues after the handler sequence when appropriate
Stack Unwinding

If the matching handler is outside the current function, C++ may exit intervening function scopes while searching for the handler. Local automatic objects are destroyed during this process.

Real-World Applications

Exception handling is useful when operations can fail in ways that should be reported to another part of the program.

File Operations

Applications can report failures when required files or resources cannot be accessed.

Banking Systems

Business operations can report exceptional conditions such as rejected transactions.

Authentication Systems

Security components can report failures that higher-level code must handle.

Database Systems

Applications can respond to connection failures and operation errors.

Network Applications

Network layers can report failed connections, timeouts, and protocol problems.

Libraries

Reusable libraries can report failures without deciding how the final application should display them.

Application Layers
User Interface
      │
      ▼
Business Logic
      │
      ▼
Service Layer
      │
      ▼
External Operation
      │
      ▼
Exceptional Failure
      │
      ▼
Exception Propagates
      │
      ▼
Appropriate Layer Handles It
Separate Detection from Response

The code that detects a problem may not be the best place to decide how the application should respond. Exceptions can transfer that responsibility to an appropriate handler.

Advantages of Exception Handling

Cleaner Control Flow

Normal logic can remain separate from exceptional handling paths.

Propagation

Failures can move through multiple function calls to an appropriate handler.

Specific Handling

Different exception types can receive different responses.

Better Diagnostics

Exception objects can carry useful information about failures.

Layer Separation

Lower-level code can report problems to higher-level application logic.

Controlled Recovery

Recoverable situations can be handled deliberately when appropriate.

  • Separates normal logic from exceptional handling.
  • Allows failures to propagate across function boundaries.
  • Supports type-based handlers.
  • Can improve error reporting.
  • Allows higher-level code to decide how to respond.
  • Works with object lifetime and stack unwinding.
  • Supports standard and custom exception types.
  • Helps structure failure-handling policies.
Exceptions Are for Exceptional Situations

Use exceptions for failures and exceptional conditions, not as a replacement for ordinary loops, conditions, or expected control flow.

Common Beginner Mistakes

Throwing Without a Suitable Handler

If an exception remains unhandled, the program ultimately terminates.

Catching the Wrong Type

A handler that does not match the thrown exception will not handle it.

Expecting Code After throw to Execute

The remaining statements in the current try execution path are skipped after the exception is thrown.

Placing catch (...) Before Specific Handlers

The catch-all handler must come after specific handlers.

Using Exceptions for Normal Decisions

Expected conditions should usually use ordinary control flow.

Catching Standard Exceptions by Value

Standard exception objects are generally caught by const reference to avoid unnecessary copying and slicing.

Unhandled Exception
int main()
{
    throw 100;

    // No handler exists
}
Wrong Handler Type
try
{
    throw 10;
}
catch (double value)
{
    // Does not handle the thrown int
}
Code After throw
try
{
    throw 10;

    // Not executed
    std::cout << "Hello";
}
catch (int value)
{
    std::cout << value;
}
Incorrect Handler Order
// ❌ Incorrect
catch (...)
{
}

catch (int value)
{
}
Correct Handler Order
// ✅ Correct
catch (int value)
{
}

catch (...)
{
}
Thrown and Caught Types Matter

Handler selection depends on C++ exception-matching rules. Do not assume ordinary numeric conversions will make unrelated catch parameter types match.

Best Practices

  • Use exceptions for exceptional situations rather than ordinary program flow.
  • Throw meaningful exception types.
  • Prefer standard exception classes when they appropriately describe the failure.
  • Create custom exception types when the application needs domain-specific information.
  • Catch the most specific exception types before more general handlers.
  • Place catch (...) last.
  • Catch standard exception objects by const reference.
  • Keep try blocks focused on operations whose exceptions you intend to handle.
  • Do not silently ignore exceptions without a deliberate reason.
  • Provide useful diagnostic information.
  • Use RAII so resources are released automatically during stack unwinding.
  • Avoid manual resource-management patterns that can leak when exceptions occur.
  • Handle an exception only when the current layer can respond meaningfully.
  • Allow exceptions to propagate when a higher layer is better suited to handle them.
  • Do not throw exceptions from destructors during stack unwinding.
Standard Exception Style
#include <iostream>
#include <stdexcept>

int main()
{
    try
    {
        throw std::runtime_error(
            "Operation failed"
        );
    }
    catch (const std::exception& error)
    {
        std::cout << error.what();
    }

    return 0;
}
Specific Before General
try
{
    // Operation
}
catch (const std::runtime_error& error)
{
    // Handle specific runtime error
}
catch (const std::exception& error)
{
    // Handle other standard exceptions
}
catch (...)
{
    // Final fallback
}

Poor Exception Design

  • Throw arbitrary values everywhere.
  • Catch every exception immediately.
  • Ignore useful error information.
  • Use exceptions for ordinary decisions.

Better Exception Design

  • Use meaningful exception types.
  • Handle errors at appropriate layers.
  • Preserve diagnostic information.
  • Use exceptions for exceptional failures.
Use RAII with Exceptions

Prefer objects such as standard containers, strings, smart pointers, and stream objects that manage their resources automatically. Their destructors participate in stack unwinding.

Frequently Asked Questions

What is an exception?

An exception is an object or value used to report an exceptional condition.

What is exception handling?

Exception handling is the mechanism used to throw, propagate, catch, and handle exceptional situations.

Which keywords are used for C++ exception handling?

The main keywords are try, throw, and catch.

What does a try block do?

A try block associates a group of statements with one or more exception handlers.

What does throw do?

throw signals an exception and transfers control away from the current normal execution path.

What does catch do?

A catch block defines a handler for a matching exception.

What happens to statements after throw?

The remaining statements in the current try execution path are skipped as exception handling begins.

Can a try block have multiple catch blocks?

Yes. Multiple handlers can process different exception types.

Do catch parameter types matter?

Yes. C++ uses exception-matching rules to select an appropriate handler.

What is catch (...)?

It is a catch-all handler that can handle exceptions not matched by earlier handlers.

Where should catch (...) be placed?

It should be placed after all specific handlers associated with the same try block.

What happens if no handler matches?

The exception continues searching through surrounding call contexts. If it remains unhandled, the program terminates.

Does division by zero automatically throw a C++ exception?

No. Integer division by zero is undefined behavior. A program must prevent the operation, for example by checking the denominator and explicitly throwing an exception.

What is stack unwinding?

Stack unwinding is the process of leaving function scopes while searching for a handler, destroying local automatic objects along the way.

Why catch standard exceptions by const reference?

It avoids unnecessary copying and helps preserve the dynamic type of polymorphic exception objects.

Should exceptions be used for normal program flow?

Generally no. Expected conditions are usually better handled with ordinary control structures.

Can we create custom exception classes?

Yes. Applications can define custom exception types for domain-specific failures.

What is std::exception?

std::exception is a standard base class used by many standard C++ exception types.

Can a program continue after handling an exception?

Yes. After a handler completes, execution can continue from the point following the associated handler sequence when the program structure allows it.

Why is exception handling useful in large applications?

It allows failures to propagate across layers and be handled where the application has enough context to respond appropriately.

Key Takeaways

  • Exception handling manages exceptional situations.
  • An exception is an object or value used to report a problem.
  • The try keyword introduces code associated with handlers.
  • The throw keyword signals an exception.
  • The catch keyword defines an exception handler.
  • Execution of the current try block stops when an exception is thrown.
  • C++ searches for a matching handler.
  • Handler selection depends on exception-matching rules.
  • Multiple catch blocks can handle different exception types.
  • Only the selected matching handler executes.
  • catch (...) is a catch-all handler.
  • The catch-all handler must appear after specific handlers.
  • Unhandled exceptions ultimately cause program termination.
  • Exceptions can propagate across function calls.
  • Stack unwinding destroys local automatic objects while scopes are exited.
  • Exception handling can separate normal logic from failure handling.
  • Integer division by zero does not automatically produce a catchable C++ exception.
  • Programs should validate dangerous operations before performing them.
  • Standard exceptions are generally caught by const reference.
  • Meaningful exception types improve diagnostics.
  • Exceptions should not replace ordinary conditions and loops.
  • Specific handlers should appear before general handlers.
  • RAII helps resources remain safe when exceptions occur.
  • Higher application layers can handle failures reported by lower layers.
  • Custom exception types can represent domain-specific failures.
  • Well-designed exception handling improves application structure and reliability.

Summary

Exception handling provides a structured mechanism for reporting and responding to exceptional situations in C++ programs.

The try keyword introduces code associated with handlers, throw signals an exception, and catch defines the code that handles a matching exception.

When an exception is thrown, the remaining statements in the current try block are skipped and C++ searches for a suitable handler. Different exception types can be handled by different catch blocks.

A catch-all handler written as catch (...) can process exceptions not matched by earlier handlers. It must appear after the specific handlers.

Exceptions can propagate through function calls. During this process, local automatic objects are destroyed as scopes are exited, a process known as stack unwinding.

Exception handling should be used for exceptional situations rather than ordinary control flow. Meaningful exception types, focused try blocks, appropriate handler placement, and RAII-based resource management help create safer designs.

C++ does not automatically turn every programming error into an exception. For example, integer division by zero is undefined behavior, so a program should detect the invalid denominator before performing the operation.

By understanding try, throw, catch, handler matching, catch-all handlers, propagation, and stack unwinding, you can design applications that respond to failures in a more controlled and maintainable way.

In the next lesson, you will learn about file handling and how C++ programs create, write, read, and manage files.

Next Lesson →

File Handling