🛑 C++ 异常处理教程(零基础版)

从0开始学习 try-catch-throw,通俗易懂 + 示例代码 + 图解风格


🔍 什么是异常处理?

在程序运行过程中,有时会遇到错误或意外情况,比如:

  • 文件找不到
  • 内存分配失败
  • 数组越界访问
  • 除以0等非法操作

如果不对这些“异常”进行处理,程序可能会崩溃甚至中止。

C++ 的异常处理机制 就是为了让程序可以优雅地应对这些错误,并尽可能恢复或给出提示,而不是直接崩溃。


⚙️ 异常处理的三要素:try, catch, throw

关键字 含义
try 包含可能抛出异常的代码块
throw 主动抛出一个异常
catch 捕获并处理异常

✅ 基本结构:

try {
    // 可能抛出异常的代码
    throw 异常对象;
} catch (异常类型 e) {
    // 处理异常
}

🧠 异常处理的工作流程图解

[ try 中发生异常 ]
        │
        ▼
   [ 抛出异常 throw ]
        │
        ▼
[ catch 捕获并处理异常 ]
        │
        ▼
[ 程序继续执行(不是崩溃)]

💡 示例一:基本异常处理

📌 场景:尝试除以0

#include <iostream>
using namespace std;

int main() {
    try {
        int a = 10, b = 0;
        if (b == 0)
            throw "除数不能为0";  // 抛出异常

        int result = a / b;  // 这里不会执行了
        cout << "结果是:" << result << endl;
    }
    catch (const char* msg) {  // 捕获字符串类型的异常
        cout << "捕获到异常:" << msg << endl;
    }

    cout << "程序继续运行..." << endl;
    return 0;
}

✅ 输出:

捕获到异常:除数不能为0
程序继续运行...

🎯 示例二:捕获多种异常类型

你可以根据抛出的不同类型来分别处理异常。

#include <iostream>
using namespace std;

int main() {
    try {
        int choice;
        cout << "请输入选择(1:整数异常, 2:浮点异常, 3:字符串异常):";
        cin >> choice;

        if (choice == 1)
            throw 100;               // 整型异常
        else if (choice == 2)
            throw 3.14;              // 浮点异常
        else if (choice == 3)
            throw "未知错误";        // 字符串异常
    }
    catch (int e) {
        cout << "捕获到整型异常:" << e << endl;
    }
    catch (double e) {
        cout << "捕获到浮点异常:" << e << endl;
    }
    catch (const char* e) {
        cout << "捕获到字符串异常:" << e << endl;
    }

    cout << "程序继续执行..." << endl;
    return 0;
}

🧩 示例三:自定义异常类(面向对象方式)

我们可以使用类来自定义更复杂的异常。

#include <iostream>
#include <string>
using namespace std;

// 自定义异常类
class MyException {
public:
    string message;
    MyException(string msg) : message(msg) {}
};

int main() {
    try {
        bool error = true;
        if (error)
            throw MyException("这是一个自定义异常!");
    }
    catch (MyException& e) {
        cout << "自定义异常信息:" << e.message << endl;
    }

    cout << "程序正常结束!" << endl;
    return 0;
}

✅ 输出:

自定义异常信息:这是一个自定义异常!
程序正常结束!

🧰 标准库中的常见异常类(需要头文件 <stdexcept>

类名 描述
std::exception 所有标准异常的基类
std::runtime_error 运行时错误,如除以0
std::range_error 结果超出范围
std::overflow_error 上溢出
std::underflow_error 下溢出
std::logic_error 逻辑错误,如无效参数
std::invalid_argument 非法参数错误
std::out_of_range 越界访问

✅ 示例四:使用标准库异常

#include <iostream>
#include <stdexcept>
using namespace std;

double divide(int a, int b) {
    if (b == 0)
        throw runtime_error("除数不能为0");
    return static_cast<double>(a) / b;
}

int main() {
    try {
        double res = divide(10, 0);
    }
    catch (runtime_error& e) {
        cout << "运行时异常:" << e.what() << endl;
    }

    cout << "程序继续执行..." << endl;
    return 0;
}

✅ 输出:

运行时异常:除数不能为0
程序继续执行...

🎨 异常处理流程图(伪代码风格)

开始
│
├─→ try 块开始
│
├─→ 如果没有异常 → 正常执行
│
├─→ 如果有异常 → throw 抛出
│
├─→ catch 块匹配异常类型
│
├─→ 处理异常
│
└─→ 继续执行后续代码

🧪 使用建议 & 最佳实践

建议 说明
🔄 不要滥用异常 只用于真正“异常”的情况,不要用作普通控制流
📦 捕获异常时尽量具体 推荐使用具体的类型(如 int, string, 自定义类),而非 ...
🧹 清理资源 catch 中也要注意释放内存、关闭文件等资源
🧠 使用基类统一处理 如果希望统一处理所有异常,可以用 catch(exception& e)
📤 使用 .what() 方法输出详细信息 对于标准异常非常实用

🧠 异常安全保证级别(高级概念)

级别 说明
No-throw guarantee 函数不会抛出任何异常
Strong guarantee 如果抛出异常,状态回滚到调用前
Basic guarantee 异常抛出后,对象仍处于有效状态
No guarantee 无法保证异常后的状态

🙋‍♂️ 如何继续学习?

如果你希望我继续扩展以下内容,请告诉我:

  • 如何用 RAII 实现异常安全?
  • 如何捕获所有异常?
  • 如何将异常与日志系统结合?
  • 如何实现嵌套异常处理结构?

😊


📌 结语:
通过本教程,你已经掌握了 C++ 异常处理的基本语法和使用场景。它是编写健壮程序的重要组成部分,特别是在大型项目中,合理的异常处理可以大大提升程序的稳定性和可维护性!

如果你还有疑问,或者想要配套练习题,也可以随时告诉我 😊

2 条评论

  • @ 2025-6-8 14:50:31
    #include <iostream>
    #include <string>
    using namespace std;
    
    // 自定义异常类
    struct MyException {
    public:
    	string message;
    	//string id;id("23")
    	MyException(string msg): message(msg)  {
    	}
    	string what(){
    		return message;
    	}
    	//MyException() {}
    	//构造函数  初始化
    };
    
    int main() {
    	try {
    		bool error = true;
    		if (error)
    			throw MyException("这是一个自定义异常!");
    	}
    	catch (MyException& e) {
    		cout << "自定义异常信息:" << e.message <<e.what()<< endl;
    	}
    	
    	cout << "程序正常结束!" << endl;
    	return 0;
    }
    
    
    • @ 2025-5-19 22:02:44

      C++ 异常处理教程(零基础版)

      C++ 异常处理是一种处理程序运行时错误的机制,它允许程序在遇到错误时能够优雅地处理问题,而不是直接崩溃。以下是针对零基础学习者的异常处理教程。

      1. 什么是异常?

      异常是程序在执行期间发生的错误或意外情况,例如:

      • 除零错误
      • 访问不存在的内存地址
      • 文件打开失败
      • 数组越界访问

      2. 异常处理的基本语法

      C++ 异常处理通过三个关键字实现:trycatchthrow

      try {
          // 可能抛出异常的代码块
          if (出现错误条件) {
              throw 异常值; // 抛出异常
          }
      }
      catch (异常类型 变量名) {
          // 处理异常的代码块
          // 可以使用变量名访问异常信息
      }
      

      3. 抛出异常 (throw)

      使用 throw 语句在程序中抛出异常。异常可以是任何数据类型(通常是类或结构体)。

      示例:除零错误处理

      #include <iostream>
      using namespace std;
      
      double divide(double a, double b) {
          if (b == 0) {
              throw "Division by zero!"; // 抛出字符串类型的异常
          }
          return a / b;
      }
      
      int main() {
          try {
              double result = divide(10.0, 0.0);
              cout << "Result: " << result << endl;
          }
          catch (const char* error) {
              cout << "Error: " << error << endl;
          }
          return 0;
      }
      

      输出:

      Error: Division by zero!
      

      4. 捕获异常 (catch)

      使用 catch 块捕获并处理异常。catch 块必须紧跟在 try 块之后。

      示例:捕获不同类型的异常

      try {
          int age = -5;
          if (age < 0) {
              throw string("Age cannot be negative!"); // 抛出 string 类型异常
          }
      }
      catch (const char* msg) {
          cout << "C-style string exception: " << msg << endl;
      }
      catch (string& msg) {
          cout << "String exception: " << msg << endl; // 捕获 string 类型异常
      }
      

      5. 多重 catch

      可以使用多个 catch 块捕获不同类型的异常,按顺序匹配。

      示例:

      try {
          // 可能抛出多种类型异常的代码
      }
      catch (int errorCode) {
          cout << "Integer error: " << errorCode << endl;
      }
      catch (double errorValue) {
          cout << "Double error: " << errorValue << endl;
      }
      catch (...) { // 捕获所有类型的异常(放最后)
          cout << "Unknown exception occurred." << endl;
      }
      

      6. 标准异常类

      C++ 标准库提供了一组异常类,位于 <exception> 头文件中。

      常见标准异常类:

      • std::exception:所有标准异常的基类
      • std::runtime_error:运行时错误
      • std::logic_error:逻辑错误
      • std::out_of_range:越界访问
      • std::invalid_argument:无效参数

      示例:使用标准异常

      #include <stdexcept> // 包含标准异常头文件
      
      int main() {
          try {
              vector<int> vec(5);
              vec.at(10) = 100; // at() 方法会抛出 out_of_range 异常
          }
          catch (const out_of_range& e) {
              cout << "Exception: " << e.what() << endl;
          }
          return 0;
      }
      

      输出:

      Exception: vector::_M_range_check: __n (which is 10) >= this->size() (which is 5)
      

      7. 自定义异常类

      可以通过继承 std::exception 类来创建自定义异常。

      示例:

      #include <stdexcept>
      #include <string>
      
      class MyException : public std::exception {
      private:
          std::string message;
      public:
          MyException(const std::string& msg) : message(msg) {}
          const char* what() const noexcept override {
              return message.c_str();
          }
      };
      
      // 使用自定义异常
      void checkAge(int age) {
          if (age < 0) {
              throw MyException("Invalid age: Age cannot be negative.");
          }
      }
      

      8. try 块嵌套

      try 块可以嵌套,内层未处理的异常会被外层 catch 捕获。

      示例:

      try {
          try {
              throw 42; // 抛出整数异常
          }
          catch (double e) {
              cout << "Inner catch: " << e << endl;
          }
      }
      catch (int e) {
          cout << "Outer catch: " << e << endl; // 捕获整数异常
      }
      

      9. 异常规范(C++11 前)

      早期 C++ 允许函数声明异常规范,但 C++11 后已弃用,推荐使用 noexcept。

      旧语法(不推荐):

      void func() throw(int, char); // 可能抛出 int 或 char 类型异常
      void safeFunc() throw();      // 不抛出任何异常
      

      现代语法:

      void func() noexcept;         // 承诺不抛出异常
      

      10. 最佳实践

      1. 只捕获能处理的异常:不要盲目捕获所有异常。
      2. 使用具体的异常类型:避免使用通用的 catch(...)
      3. 异常安全性:确保资源释放(如文件关闭、内存释放)。
      4. 自定义异常:为特定错误创建有意义的异常类。
      5. 避免异常泄露:析构函数和 noexcept 函数不应抛出异常。

      总结

      异常处理是 C++ 中处理错误的强大机制,通过 trycatchthrow 可以优雅地处理运行时错误,提高程序的健壮性。建议结合标准异常类和自定义异常类,根据实际需求选择合适的异常处理策略。

      通过练习上述示例,你可以掌握 C++ 异常处理的基础知识。

      • 1