C++ | 掌握C++异常处理:从基础到自定义异常体系的全面指南

目录

09--异常

1、C语言传统的错误处理方式:

2、C++异常概念:

3、异常的使用:

4、自定义继承的异常体系:

5、C++标准库的异常体系:

6、异常的优缺点:


09--异常

1、C语言传统的错误处理方式

包括终止程序和返回错误码两种方式。

直接使用assert终止程序过于粗暴:用户无意的小错误也会造成程序结束运行。

return返回错误码,再通过错误码查找错误类型:过程繁琐,对用户专业要求高。

2、C++异常概念

异常是一种错误处理机制,通过throw抛出异常,并通过trycatch进行捕获和处理。

try
    {
  // 正常业务代码(会抛出异常)
}catch( Exception e1 )
    {
  // 异常情况1
}catch( Exception e2 )
    {
  // 异常情况2
}catch( ... )
    {
  // 捕捉剩余异常
}

3、异常的使用
    • 异常的抛出和捕获遵循类型匹配原则,声明的异常类型不会隐式类型(int不会匹配double、const char* 不会匹配 string)
    • 异常对象抛出后会生成拷贝,原始对象在捕获后销毁。
    • catch(...)可以捕获任意类型的异常。
#include<iostream>
using namespace std;
double Division(double a, double b)
{
    if (b == 0)
    {
        throw "[error] b == 0";
    }
    return a / b;
}


int main()
{
    try
    {
        cout << (Division(1, 0));
    }
    catch (const char* errmsg)
    {
        cout << errmsg << endl;
    }

    return 0;
}
    • 异常的重新抛出允许异常传递给更外层的函数处理。
    • 异常安全强调在构造函数和析构函数中避免抛出异常,以防止资源泄漏。
    • 异常规范说明了函数可能抛出的异常类型。
double Division(double a, double b) throw(const char*)                                 
{                                // 异常规范 表示这个函数只会抛出的异常类型
    if (b == 0)
    {
        throw "[error] b == 0";
    }
    return a / b;
}

double Add(double a, double b) throw() 
{                            // 表明不会抛出异常 c++11后可以使用noexcept
    return a + b;
}

4、自定义继承的异常体系

异常的捕捉同样支持“多态”,捕捉基类对象的声明会同时捕捉派生类对象。

公司或项目一般都会利用此机制自定义一套异常体系,以规范异常的使用和管理。

#include<iostream>
using namespace std;
class error
{
public:
    error(const string& s)
        :_errmsg(s)
    {}
protected:
    string _errmsg;
};

class numerror :public error
{
public:
    numerror(const string& msg, int x)
        :error(msg),
        _a(x)
    {}
    friend ostream& operator<<(ostream& out, const numerror& x);
private:
    int _a;
};

ostream& operator<<(ostream& out, const numerror& x)
{
    out << x._errmsg << ' ' << x._a << endl;
    return out;
}

double Division(double a, double b) throw(error) // 异常规范 表示这个函数只会抛出的异常类型
{
    if (b == 0)
    {
        throw numerror("[error] b == 0", b);
    }
    return a / b;
}

double Add(double a, double b) throw() // 表明不会抛出异常 c++11后可以使用noexcept
{
    return a + b;
}


int main()
{
    try
    {
        cout << (Division(1, 0)) << endl;
    }
    catch (numerror errmsg)
    {
        cout << errmsg << endl;
    }
    return 0;
}

解释:

    • error 类是一个基类,用于存储错误信息。
    • numerror 类继承自 error 类,增加了一个整数成员 _a 来存储与数字相关的错误信息。
    • Division 函数声明时使用了 throw(error) 来指定函数可能抛出的异常类型。这意味着 Division 函数只会抛出 error 类或其派生类的实例。

在代码的抛出规范声明、捕捉类型声明都只需要写基类对象类型,就可以智能多态地完成捕获。

5、C++标准库的异常体系

C++提供了一系列的标准异常类,以层次结构组织。

#include<iostream>
#include<vector>
using namespace std;
int main()
{
    try {
        vector<int> v(10, 5);
        v.reserve(10);
        // 越界抛异常:invalid vector subscript 无效的向量下标
        v.at(10) = 100;
    }
    catch (const exception& e) // 捕获基类对象即可 
    {
        cout << e.what() << endl;
    }
    catch (...)
    {
        cout << "Unkown Exception" << endl;
    }
    return 0;
}

exception是c++提供的异常类,可以将exception作为基类构建自己的异常体系。

6、异常的优缺点
    • 优点包括清晰的错误信息展示、简化深层函数错误处理、第三方库支持、适合特定函数的错误处理。
    • 缺点包括可能导致程序执行流程混乱、性能开销、资源管理问题、标准库异常体系设计不佳、使用不规范可能导致的问题。

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值