• STL教程3-异常机制


    可以跳过直接看总结 

    目录

    1、基本异常语法

    2、异常向上抛,一直到顶层

    3、栈解旋

    4、异常接口声明

    5、抛出异常对象

    5、异常类型和异常变量的声明周期

    6、异常标准类 

     7、继承在异常中的应用

     8、总结


    1、基本异常语法

    throw ,然后对应的try.....catch ...

    2、异常向上抛,一直到顶层

    异常会一层一层的向上抛,如果异常抛到顶层还没有被处理,那么此时程序会使用terminate()去终止程序,c++的异常处理机制是跨函数的。

    3、栈解旋

    所以throw很类似return,其实就是局部变量离开它的工作空间,会自动的调用析构函数

    4、异常接口声明

    在函数上声明throw只会抛出指定的数据类型,如果是其他的数据类型会报错。

    但是下面在vs2022没有报错

    1. //声明这个函数只会抛出int float char三种类型的异常,抛出其他的就会报错
    2. void func()throw (int, float, char) {
    3. throw "abc";
    4. }
    5. //不能抛出任何异常
    6. void func02()throw() {
    7. throw -1;
    8. }
    9. int main() {
    10. try{
    11. func02();
    12. }
    13. catch (char* str) {
    14. cout << str << endl;
    15. }
    16. catch (int e) {
    17. cout << "异常" << endl;
    18. }
    19. catch (...) {//捕获所有异常
    20. cout << "未知类型异常" << endl;
    21. }
    22. }

    5、抛出异常对象

    • throw的异常是有类型的,可以是数字、字符串、类对象
    • throw的异常是有类型的,catch需严格匹配异常类型

     

    1. class MyExcept {
    2. public :
    3. void what() {
    4. cout << "抛出一个异常";
    5. }
    6. };
    7. void func03() {
    8. throw MyExcept();//抛出了一个匿名对象
    9. }
    10. int main() {
    11. try{
    12. func03();
    13. }
    14. catch (MyExcept e) {
    15. e.what();
    16. }
    17. }

     下面是对对象加了点东西

     上面内存泄露了

    需要加上析构函数~MyExcept(){if(error!=NULL)delete[]error;}。而且拷贝的时候也会出错

     因此正常代码如下

    1. class MyExcept {
    2. public:
    3. char* error;
    4. public :
    5. MyExcept(char* str) {
    6. error = new char[strlen(str) + 1];
    7. strcpy(error, str);
    8. }
    9. MyExcept(const MyExcept& ex) {
    10. this->error = new char[strlen(ex.error) + 1];
    11. strcpy(this->error, ex.error);
    12. }
    13. MyExcept& operator=(const MyExcept& ex) {
    14. if (this->error != NULL) {
    15. delete[]this->error;
    16. this->error = NULL;
    17. }
    18. this->error = new char[strlen(ex.error) + 1];
    19. strcpy(this->error, ex.error);
    20. }
    21. ~MyExcept() {
    22. if (error != NULL)
    23. delete[]error;
    24. }
    25. void what() {
    26. cout << error << endl;
    27. }
    28. };
    29. void func03() {
    30. char* str ;
    31. strcpy(str, "这是一个异常");
    32. throw MyExcept(str);//抛出了一个异常对象
    33. }
    34. int main() {
    35. try{
    36. func03();
    37. }
    38. catch (MyExcept e) {
    39. e.what();
    40. }
    41. }

    5、异常类型和异常变量的声明周期

    上一个小段的生命周期为

    throw的匿名函数会首先调用异常对象的构造函数,然后被catch捕获会调用拷贝函数,

     这里普通元素异常函数处理完成后就会被析构

    将上面catch改为引用,引用也是catch处理完成后调用析构函数

     换成指针

     既然不能用匿名函数,那么可以new一个,然后在处理完成后再析构

    6、异常标准类 

    参考c++标准库异常以及编写自己的异常类的写法_xujianjun229的博客-CSDN博客

     由于标准库的异常是有限的,因此需要编写自己的异常类

    但是编写异常类需要注意以下几点

    ① 建议自己的异常类要继承标准异常类。因为 C++中可以抛出任何类型的异常,所以我们 的异常类可以不继承自标准异常,但是这样可能会导致程序混乱,尤其是当我们多人协同开 发时。

    ② 当继承标准异常类时,应该重载父类的 what 函数和虚析构函数。

    ③ 因为栈展开的过程中,要复制异常类型,那么要根据你在类中添加的成员考虑是否提供 自己的复制构造函数

    下面是使用标准库异常的例子

    这里使用上图的out_of_range,可以看到属于<stdexcept>,因此包含那个头文件

    下面写自己的异常类,这个异常类继承于exception

     7、继承在异常中的应用

    这里写个能处理各种异常的情况

     注意析构函数必须定义而不能仅仅是声明,因此加上{}

    1. class BaseMyException {
    2. public:
    3. virtual void what() = 0;
    4. virtual ~BaseMyException() {};
    5. };
    6. class sourceException:public BaseMyException {
    7. public:
    8. virtual void what() {
    9. cout << "目标空间为空" << endl;
    10. }
    11. virtual ~sourceException() {}
    12. };
    13. class tagetException :public BaseMyException {
    14. public:
    15. virtual void what() {
    16. cout << "目标空间为空" << endl;
    17. }
    18. virtual ~tagetException() {}
    19. };
    20. void copy_str(char* taget,const char* source) {
    21. if (taget == NULL)throw sourceException();
    22. if (source == NULL)throw tagetException();
    23. while (*source != '\0') {
    24. *taget = *source;
    25. taget++;
    26. source++;
    27. }
    28. *taget = '\0';
    29. }
    30. int main() {
    31. const char* source = "abncdedf";
    32. char buf[1024] = { 0 };
    33. try
    34. {
    35. copy_str(NULL, source);
    36. }
    37. catch (BaseMyException& e)
    38. {
    39. e.what();
    40. }
    41. cout << buf << endl;
    42. }

     8、总结

    1、异常向上抛,一直到顶层,到顶层还不处理会终止程序

    2、栈解旋,throw很类似return,函数里进行throw后,函数定义的局部变量会被析构

    3、异常接口声明,void func()throw (int, float, char) {...}声明以后,函数里只能抛出这三种异常,但是在windows下貌似不起作用

    4、throw的异常是有类型的,可以是数字、字符串、类对象,这个类对象可以是自己写的一个类,比如类里面有个string变量存放消息,throw后使用构造函数给这个变量赋值,然后catch调用打印函数,这个类也可以是继承标准异常类。

    5、对于标准库异常类的使用有两种方法,标准库也和第四条一样有一个变量,以out_of_range类为例,第一种是扔出一个out_of_range对象,即throw out_of_range(“这里给变量赋值”);第二种方法是写一个类继承标准库异常类,定义一个存放信息的变量,写自己的构造方法给变量赋值,重写what()方法,重写析构函数,然后catch时用基类统一接收

    6、异常处理完成后对象就会被析构,即异常对象的生命周期在catch后结束

    7、写各种情况的异常类,这些类继承于一个基类,在catch时只用基类接收就可以

     

     

  • 相关阅读:
    muduo源码剖析之EventLoopThreadPool
    企业数据共享机制的建立,是一次企业内部的重新梳理
    c语言-数据结构-栈和队列的实现和解析
    编写一个人民币与输入币种的兑换程序,根据用户输入的币种、汇率和待兑换人民币数量,实现人民币到其他币种的兑换。
    19. input( )输入函数课后练习
    如何使用libswscale库将YUV420P格式的图像序列转换为RGB24格式输出?
    C语言编程陷阱(三)
    谷粒学院——后台管理系统功能模块
    Canvas 低代码工具,多人自研开发全流程优化|ModelWhale 版本更新
    uni-app:js实现数组中的相关处理-数组复制
  • 原文地址:https://blog.csdn.net/baidu_41553551/article/details/125380668