09--异常
1、C语言传统的错误处理方式:
包括终止程序和返回错误码两种方式。
直接使用assert终止程序过于粗暴:用户无意的小错误也会造成程序结束运行。
return返回错误码,再通过错误码查找错误类型:过程繁琐,对用户专业要求高。
2、C++异常概念:
异常是一种错误处理机制,通过throw抛出异常,并通过try和catch进行捕获和处理。
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、异常的优缺点:
-  
  
- 优点包括清晰的错误信息展示、简化深层函数错误处理、第三方库支持、适合特定函数的错误处理。
 - 缺点包括可能导致程序执行流程混乱、性能开销、资源管理问题、标准库异常体系设计不佳、使用不规范可能导致的问题。
 
 



















