C++基础——15.3异常

C++异常 abnormal

  • 基本语法
    void run() 
    {
          
          
    	/* 第一次抛出 */
    	if (error) {
          
          
    		throw;
    	}
    }
    
    int call()
    {
          
          
    	try {
          
          
    		/* 复合语句 */
    		run();
    	} catch (int e) {
          
           /* 异常类型声明 */
    		/* 复合语句 */
    		/* 第二次抛出,接受到异常, 可以不处理继续向外扔 */
    		处理异常 or  throw 继续抛出
    	} catch (类型 (形参)){
          
           
    		/* 复合语句 */
    	} catch (...) {
          
          
    		/* 复合语句 */
    		未知异常 or throw 继续抛出
    	}
    	return 0;
    }
    
    int main()
    {
          
          
    	call();
    }
    
  • 例1
    #include <iostream>
    
    void divide(int x, int y)
    {
          
          
        if (y == 0) {
          
          
            throw x;
        }
        std::cout << "result = " << x / y << std::endl;
    }
    
    int main()
    {
          
          
        try {
          
          
            divide(10 ,0);        
        } catch (int e) {
          
          
            std::cout << e << "被零除" << std::endl;
        } catch (...) {
          
          
            std::cout << "其他异常" << std::endl;
        }
        return 0;
    }
    
  • 异常结论
    1. 若有异常则通过throw操作创建一个异常对象并抛出
    2. 将可能抛出异常的程序段嵌套在try块之中,控制通过正常的顺序到达try语句,然后执行try块内的保护段
    3. 如果在保护段执行期间没有引发异常,那么跟在try块后的catch子句就不执行,则跳过try catch块继续执行
    4. catch子句按其在try块后出现的顺序被检查,匹配到catch子句将捕获并处理异常(或基础抛出)
    5. 如果匹配的处理器未找到,则运行函数terminate将被自动调用,其缺省功能是调用abort终止程序
    6. 处理不了的异常,可以在catch的最后一个分支,使用throw语法,向上抛出
  • 栈解退 (Stack unwinding)

    异常被抛出后,从进入try块起,到异常被抛掷前,这期间在栈上的构造的所有对象,都会被自动析构。析构的顺序与构造的顺序相反。这一过程称为栈解退(unwinding)

    #include <iostream>
    
    using namespace std;
    
    class T {
          
          
    public:
        T(int x = 0, int y = 1) {
          
          
            this->x = x;
            this->y = y;
            cout << "construct\n";
        }
        ~T() {
          
          
            cout << "deconstruct\n";
        }
    private:
        int x;
        int y;
    };
    
    void divide()
    {
          
          
        T t1(10, 2), t2(20, 1);
        cout << "throw abnormal\n";
        throw 1; 
    }
    int main()
    {
          
          
        try {
          
          
            divide();
        } catch (int e) {
          
          
            cout << "integer type abnormal\n";
        } catch (...) {
          
          
            cout << "unknow abnormal\n";
        }
        return 0;
    }
    /* 输出 */
    /*
    construct
    construct
    throw abnormal
    deconstruct
    deconstruct
    integer type abnormal
    */
    
  • 异常规范与C++11

    异常规范(exception specification)是C++98新增的一项功能,但是在C++11被摒弃,它的语法如下

    //1) 为了加强可读性,可以在函数声明中列出可能抛出的所有异常,
    	void func() throw(A, B, C, D); // 这个函数只抛出类型为A B C D及其子类型的异常
    // 2) 如果在函数声明中没有包含异常接口声明,则此函数可以抛掷任何类型的异常,例如
    	void func(); // 函数func可抛出任何类型异常
    // 3) 一个不抛掷任何类型异常的函数可以声明为:
    	void func() throw();	 // 函数func不抛出任何异常 
    // 4) 如果一个函数抛出了它的异常接口声明所不允许抛出的异常,unexpected函数会被调用,该函数默认行为调用teminate函数终止程序
    

    C++11支持一种特殊的异常规范:关键字noexcept指出函数不会引发异常

    double func() noexcept; // 指出func不会引发异常
    
  • 异常类型&异常变量的声明周期
    1. 如果接收异常时 使用一个异常变量,则拷贝构造异常变量
    2. 如果使用引用,会使用throw时的那个对象
    3. 如果使用指针,指针可以和引用元素一起使用,但是引用/元素不可以一起使用

猜你喜欢

转载自blog.csdn.net/gripex/article/details/105108248