C++: Exception Handling

Last updated: 2026-08-26

When programs run, unexpected things always happen: files don't exist, memory runs out, network disconnects...

If left unhandled, the program crashes.

Exception handling is the program's "airbag" — when problems occur, it responds gracefully instead of crashing outright.


1. Exception Handling Basics

(1) 1.1 What Is an Exception?

An exception is an error or unexpected condition that occurs during program execution.

Common Exceptions:


(2) 1.2 The Three Elements of Exception Handling

C++ exception handling uses three keywords:

Keyword Function
try Monitor code that may throw errors
catch Catch and handle exceptions
throw Throw an exception

(3) 1.3 Basic Example

Example: Division by Zero Exception (Difficulty ⭐)

▶ Example 1: Code Example (Difficulty ⭐)

CPP
#include <iostream>

int divide(int a, int b) {
 if (b == 0) {
 throw "Divisor cannot be 0!"; // Throw exception
 }
 return a / b;
}

int main() {
 try {
 std::cout << divide(10, 2) << std::endl; // Normal
 std::cout << divide(10, 0) << std::endl; // Throws exception
 }
 catch (const char* msg) { // Catch exception
 std::cerr << "Error: " << msg << std::endl;
 }
 
 std::cout << "Program continues running" << std::endl;
 return 0;
}
▶ Try it Yourself

Output:

TEXT 📖 Display only
5
Error: Divisor cannot be 0!
Program continues running

Execution Result:

TEXT 📖 Display only
5
Error: Divisor cannot be 0!
Program continues running

💡 Tip:



2. Exception Types

(1) 2.1 Types That Can Be Thrown

throw can throw any type:

Type Example
Basic types throw 42;
Strings throw "error";
Standard exceptions throw std::runtime_error("error");
Custom exceptions throw MyException();

(2) 2.2 Catching Multiple Exceptions

Example: Catching Different Types of Exceptions (Difficulty ⭐⭐)

CPP
#include <iostream>
### ▶ Example 2: Code Example (Difficulty ⭐)

#include <string>

void process(int value) {
 if (value == 0) {
 throw 0; // Throw int
 }
 if (value < 0) {
 throw std::string("Negative number"); // Throw string
 }
}

int main() {
 try {
 process(-5);
 }
 catch (int e) {
 std::cerr << "Caught int exception: " << e << std::endl;
 }
 catch (const std::string& e) {
 std::cerr << "Caught string exception: " << e << std::endl;
 }
 
 return 0;
}


3. Standard Exceptions

(1) 3.1 std::exception Hierarchy

The C++ standard library defines a set of exception classes, all in stdexcept:

TEXT 📖 Display only
std::exception
 ├── std::logic_error
 │ ├── std::invalid_argument
 │ ├── std::out_of_range
 │ └── std::length_error
 └── std::runtime_error
 ├── std::overflow_error
 └── std::underflow_error

(2) 3.2 Common Standard Exceptions

Exception Class Description
std::invalid_argument Invalid argument
std::out_of_range Out of bounds
std::runtime_error Runtime error
std::bad_alloc Memory allocation failure (new failed)

Example: Using Standard Exceptions (Difficulty ⭐⭐)

CPP
#include <iostream>
#include <stdexcept>
#include <vector>

int main() {
 std::vector<int> v = {1, 2, 3};
 
 try {
 v.at(10); // Out-of-bounds access
 }
 catch (const std::out_of_range& e) {
 std::cerr << "Caught exception: " << e.what() << std::endl;
 }
 
 return 0;
}


4. Custom Exceptions

(1) 4.1 Inheriting from std::exception

Best Practice: Custom exception classes should inherit from std::exception.

Example: Custom Exception Class (Difficulty ⭐⭐⭐)

CPP
#include <iostream>
#include <exception>
#include <string>

// Custom exception class
class MyException : public std::exception {
private:
 std::string msg;
 
public:
 MyException(const std::string& msg) : msg(msg) {}
 
 const char* what() const noexcept override {
 return msg.c_str();
 }
};

int main() {
 try {
 throw MyException("Custom exception");
 }
 catch (const MyException& e) {
 std::cerr << "Caught custom exception: " << e.what() << std::endl;
 }
 
 return 0;
}


5. Exception Safety

(1) 5.1 What Is Exception Safety?

Exception safety means that even when an exception is thrown, the program maintains a consistent state (no resource leaks, no data corruption).

Three guarantee levels:

  1. Basic guarantee: The program state is consistent, but may have changed
  2. Strong guarantee: The operation either succeeds or is completely rolled back (as if it never happened)
  3. No-throw guarantee: The function never throws an exception

(2) 5.2 RAII — A Powerful Tool for Resource Management

RAII (Resource Acquisition Is Initialization): Manage resources through objects, with destructors automatically releasing them.

Example: Using Smart Pointers for Exception Safety (Difficulty ⭐⭐⭐)

CPP
#include <iostream>
#include <memory>

void process() {
 // Use unique_ptr to manage memory; even if an exception is thrown, it will be automatically freed
 std::unique_ptr<int> p(new int(42));
 
 // ... code that may throw exceptions ...
 
 std::cout << *p << std::endl;
} // p is automatically freed

int main() {
 try {
 process();
 }
 catch (...) {
 std::cerr << "Caught exception" << std::endl;
 }
 return 0;
}


6. The noexcept Keyword

(1) 6.1 Basic Usage

C++11 introduced noexcept, which declares that a function does not throw exceptions.

Example: Declaring No-Throw (Difficulty ⭐)

TEXT 📖 Display only
void safeFunction() noexcept {
 // This function guarantees not to throw exceptions
}

void unsafeFunction() {
 // May throw exceptions
}

💡 Tip:


❓ FAQ

Q: When should I use exceptions? A: For truly unexpected situations, not for normal control flow.


Q: What is catch(...)? A: It catches all exceptions, typically used to clean up resources before re-throwing.

CPP
try {
 // ...
}
catch (...) {
 // Clean up resources
 throw; // Re-throw
}

Q: Can constructors throw exceptions? A: Yes, but be careful about memory leaks. Use smart pointers or RAII to manage resources.


▶ Example 3: Catching Exceptions (Difficulty ⭐)

CPP
#include <iostream>
#include <stdexcept>

double divide(double a, double b) {
    if (b == 0) {
        throw std::runtime_error("Divisor cannot be 0");
    }
    return a / b;
}

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

    return 0;
}
▶ Try it Yourself

Output:

TEXT 📖 Display only
Error: Divisor cannot be 0
💡 Tip: try-catch catches exceptions, throw throws exceptions. what() returns the error message.


Concept Key Point
try-catch-throw The three elements of exception handling
Standard exceptions std::runtime_error, etc.
Custom exceptions Inherit from std::exception
Exception safety RAII ensures no resource leaks
noexcept Declares that a function does not throw

📖 Summary

📝 Exercises

  1. Basic (Difficulty ⭐): Write a division function that throws std::runtime_error when the divisor is 0, and use try/catch in main to catch and output the error message.

  2. Intermediate (Difficulty ⭐⭐): Define a custom exception class (inheriting from std::exception) with two fields: error code and error description. After throwing it, retrieve both in the catch block.

  3. Challenge (Difficulty ⭐⭐⭐): Implement a "resource guard" class that acquires resources in the constructor and releases them in the destructor. Even if an exception is thrown in between, resources are correctly released (RAII principle).



Next Lesson: Advanced File Operations (#41)

Web-Tutorial.com

Web-Tutorial Tech Team

A team of developers maintaining programming tutorials. Each tutorial is written and reviewed by developers with expertise in that field. We work to keep our content accurate and reliable — if you spot an issue, please let us know.

100%

🙏 帮我们做得更好

我们是刚上线的编程教程站,几个人的小团队,精力有限。页面虽经检查,难免还有疏漏——链接失效、排版错乱、内容有误、语言生硬……

如果您发现了,麻烦告诉我们,我们会在收到反馈后第一时间进行修复,再次感谢您的光临 🙏