用户_29571846
发布于 2026-06-22 / 1 阅读
0
0

C++ 异常捕获 try-catch-throw 错误处理完整教程

一、前言

程序运行时会出现不可预判错误:除数为 0、文件打开失败、数组越界、空指针访问。传统 if 判断只能简单拦截,异常机制可以统一捕获、分层处理运行时错误,避免程序直接崩溃。本篇讲解throw抛出异常、try-catch捕获、自定义异常类实战。

二、异常基础三要素

  1. throw:主动抛出异常,触发错误信号

  2. try:包裹可能出错的代码块,监控异常

  3. catch:匹配对应类型异常,编写错误修复逻辑

基础语法模板

cpp

运行

try
{
    // 风险代码,可能抛出异常
    throw 异常数据;
}
catch(异常类型1 接收变量)
{
    // 处理类型1错误
}
catch(异常类型2 接收变量)
{
    // 处理类型2错误
}

三、基础案例:除数为 0 异常捕获

cpp

运行

#include <iostream>
using namespace std;
double calcDiv(int a, int b)
{
    if(b == 0)
    {
        // 抛出字符串异常
        throw "除数不能为0,运算非法";
    }
    return (double)a / b;
}
int main()
{
    int x, y;
    cout << "输入被除数、除数:";
    cin >> x >> y;
    try
    {
        double res = calcDiv(x, y);
        cout << "计算结果:" << res << endl;
    }
    catch(const char *errMsg)
    {
        // 捕获抛出的字符串异常
        cout << "运行错误:" << errMsg << endl;
    }
    return 0;
}

运行输入10 0,不会直接闪退,而是输出自定义错误提示。

四、多类型异常分层捕获

一段 try 代码可抛出不同类型异常,多个 catch 从上到下依次匹配:

cpp

运行

void test(int num)
{
    if(num < 0)
        throw num; // int类型异常
    else if(num > 100)
        throw "数值超出0~100范围"; // 字符串异常
    else
        throw 3.14; // double异常
}
int main()
{
    int n;
    cin >> n;
    try
    {
        test(n);
    }
    catch(int e)
    {
        cout << "错误:负数 " << e << endl;
    }
    catch(const char *e)
    {
        cout << "错误提示:" << e << endl;
    }
    catch(double e)
    {
        cout << "浮点异常:" << e << endl;
    }
    return 0;
}

五、通用捕获 catch(...) 兜底所有异常

不确定抛出异常类型时,使用省略号捕获任意异常,必须放在所有 catch 最后:

cpp

运行

try
{
    // 任意风险代码
}
catch(int e)
{
}
catch(...)
{
    cout << "发生未知类型运行异常" << endl;
}

六、标准库内置异常类(std::exception)

C++ 标准库提供统一异常基类,包含文件、内存、范围、IO 错误,头文件<exception>

常用子类:

  • runtime_error:运行时通用错误

  • out_of_range:数组 / 字符串下标越界

  • logic_error:逻辑参数错误

  • bad_alloc:new 分配内存失败

标准异常使用示例

cpp

运行

#include <iostream>
#include <exception>
#include <string>
using namespace std;
void checkScore(int s)
{
    if(s < 0 || s > 100)
    {
        throw out_of_range("分数必须在0~100之间");
    }
}
int main()
{
    int score;
    cin >> score;
    try
    {
        checkScore(score);
        cout << "分数合法" << endl;
    }
    catch(const exception &e)
    {
        // what() 返回异常描述文本
        cout << "异常:" << e.what() << endl;
    }
    return 0;
}

七、自定义异常类(大型项目规范写法)

继承std::exception重写what(),区分业务错误:

cpp

运行

#include <iostream>
#include <exception>
#include <string>
using namespace std;
// 自定义文件操作异常
class FileErr : public exception
{
public:
    string msg;
    FileErr(string s):msg(s){}
    const char* what() const noexcept override
    {
        return msg.c_str();
    }
};
void openFile()
{
    bool openSuccess = false;
    if(!openSuccess)
        throw FileErr("目标txt文件不存在,打开失败");
}
int main()
{
    try
    {
        openFile();
    }
    catch(const FileErr &e)
    {
        cout << "文件异常:" << e.what() << endl;
    }
    catch(const exception &e)
    {
        cout << "系统异常:" << e.what() << endl;
    }
    return 0;
}

八、异常传递与函数声明 throw

函数后可声明可能抛出的异常类型,规范接口:

cpp

运行

// 声明该函数只会抛出int、string异常
void func() throw(int, const char*);

若函数抛出未声明异常,程序直接终止。

九、新手避坑

  1. catch 捕获类型必须和 throw 抛出类型严格匹配,否则匹配失败触发兜底

  2. 标准异常捕获必须用const exception &引用,避免拷贝丢失信息

  3. 异常未被任何 catch 捕获,程序直接调用abort()强制退出

  4. 析构函数禁止主动抛出异常,会造成内存资源泄漏

  5. catch(...)只能捕获,无法获取异常详情,仅做兜底容错

十、综合实战:带异常校验的学生成绩录入系统

cpp

运行

#include <iostream>
#include <exception>
using namespace std;
void inputScore(int score)
{
    if(score < 0)
        throw runtime_error("分数不能为负数");
    if(score > 100)
        throw runtime_error("分数不能超过100");
    cout << "录入成功,分数:" << score << endl;
}
int main()
{
    int s;
    cout << "输入考试分数:";
    cin >> s;
    try
    {
        inputScore(s);
    }
    catch(const runtime_error &err)
    {
        cout << "录入失败:" << err.what() << endl;
    }
    return 0;
}

十一、下期预告

下一篇:C++ STL 容器:vector 动态可变数组完整实战教程


评论