C++ 错误处理:try/catch 从 A 到 Z – 完整指南

面向初学者的在线Python训练器

轻松学习Python,无需理论负担。在浏览器中直接解决带自动检查的实践任务,无需安装任何东西。

开始课程

引言:为什么错误处理是 C++ 可靠代码的基石



任何与外部世界(文件、网络、用户输入)交互的程序都不可避免地会遇到异常情况。在 C++ 中,try/catch 机制是优雅且可控地管理此类情况的主要工具。在本文中,我们将从基本结构到高级技术,包括最佳实践和陷阱,全面解析 C++ 中的错误处理。



1. 基础:try、catch 和 throw



C++ 中的异常机制建立在三个关键关键字之上:try、catch 和 throw。



1.1. try 和 catch 块

try 块包含可能抛出异常的代码。catch 块捕获该异常并进行处理。



#include <iostream>#include <stdexcept>

int main() { try { // 可能引发错误的代码 int age = -5; if (age < 0) { throw std::invalid_argument("年龄不能为负数"); } std::cout << "年龄: " << age << std::endl; } catch (const std::invalid_argument& e) { std::cerr << "错误: " << e.what() << std::endl; } return 0;}


1.2. 异常类型

在 C++ 中,可以抛出任何类型的异常:数字、字符串、类对象。但建议使用 <stdexcept> 中的标准异常类,或创建继承自 std::exception 的自定义类。



  • 标准异常:std::runtime_error、std::logic_error、std::out_of_range 等。
  • 自定义异常:通过继承 std::exception 创建。


class MyException : public std::exception {public:    const char* what() const noexcept override {        return "我的自定义异常";    }};


1.3. 多个 catch 块

您可以在单独的 catch 块中捕获不同类型的异常。顺序很重要:更具体的异常应放在前面。



try {    // 代码} catch (const std::invalid_argument& e) {    // 处理 invalid_argument} catch (const std::exception& e) {    // 处理所有其他 std 异常} catch (...) {    // catch-all:捕获上面未捕获的所有异常}


2. 高级技术:栈展开与 RAII



2.1. 栈展开(Stack Unwinding)

当抛出异常时,C++ 会自动销毁从 throw 点到相应 catch 路径上的所有局部对象。这个过程称为栈展开。它保证为在 try 块中创建的所有对象调用析构函数。



class Resource {public:    Resource() { std::cout << "资源已创建"; }    ~Resource() { std::cout << "资源已销毁"; }};

void riskyFunction() { Resource res; throw std::runtime_error("出问题了");}

int main() { try { riskyFunction(); } catch (const std::exception& e) { std::cerr << e.what() << std::endl; } // 输出:资源已创建 -> 资源已销毁 -> 出问题了}


2.2. RAII(资源获取即初始化)

RAII 是 C++ 中与错误处理密切相关的关键惯用法。其思想是:资源管理(内存、文件、互斥锁)与对象的生命周期绑定。即使发生异常,析构函数也会自动释放资源。



  • 智能指针:std::unique_ptr、std::shared_ptr

博客

书籍推荐