C++异常处理

github代码提交记录

异常处理机制

  1. 若是有异常则通过throw操作创建一个异常对象并抛掷
  2. 将可能抛出异常的程序段嵌入到try块之中,控制通过正常的顺序执行到try语句,然后执行try块内的保护段
  3. 如果在保护段执行期间没有引起异常,那么跟在try块后的catch子句就不执行,程序从try块后跟随者最后一个catch子句后面的语句继续执行下去。
  4. catch子句按其在try块后出现的顺序被检查,匹配的catch子句将捕获并处理异常
  5. 如果匹配的处理器未找到,则执行函数teminate将自动调用,其缺省功能是调用abort终止程序
  6. 处理不了的异常,可以在catch的最后一个分支,使用throw的方法继续向上扔

异常处理的好处就是能将异常处理和正常函数流程进行分离,正常流程只处理函数业务上的逻辑,异常处理可以交给单独的异常处理函数进行处理。

栈解旋

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

异常接口声明

为了加强程序的可读性,可以在函数声明中列出可能抛出的所有异常类型,例如:void func() throw(A,B,C,D),这个函数func()能够且只能抛出A,B,C,D及其子类型的异常。

如果函数声明中国捏没有包含任何类型的异常接口声明,则此函数可以抛出任何类型的异常,例如:void func()

一个不抛出任何异常的函数可以声明为void func() throw()

如果一个函数抛出了它的异常接口声明不允许抛出的异常,unexpected函数会被调用,该函数默认行为调用terminate函数终止程序。

C++标准异常

在这里插入图片描述

异常 描述
std::exception 该异常是所有标准 C++ 异常的父类。
std::bad_alloc 该异常可以通过 new 抛出。
std::bad_cast 该异常可以通过 dynamic_cast 抛出。
std::bad_exception 这在处理 C++ 程序中无法预期的异常时非常有用。
std::bad_typeid 该异常可以通过 typeid 抛出。
std::logic_error 理论上可以通过读取代码来检测到的异常。
std::domain_error 当使用了一个无效的数学域时,会抛出该异常。
std::invalid_argument 当使用了无效的参数时,会抛出该异常。
std::length_error 当创建了太长的 std::string 时,会抛出该异常。
std::out_of_range 该异常可以通过方法抛出,例如 std::vector 和 std::bitset<>::operator
std::runtime_error 理论上不可以通过读取代码来检测到的异常。
std::overflow_error 当发生数学上溢时,会抛出该异常。
std::range_error 当尝试存储超出范围的值时,会抛出该异常。
std::underflow_error 当发生数学下溢时,会抛出该异常。

//
// Created by andrew on 2021/4/24.
//
#include <iostream>
#include <exception>

using  namespace std;

/*
 * 异常的基本语法
 * */

class error : std::exception {
    const char * what() const noexcept override;
};

const char *error::what() const noexcept {
    return exception::what();
}

class construct_test {
public:
    construct_test() {
        cout << "construct test" << endl;
    };
    ~construct_test() {
        cout << "destruct test" << endl;
    }
};

int divide_demo(int x, int y) {

    construct_test constTest;

    if (y == 0) {
        cout << "before throw " << endl;
        // throw之前将所有的栈进行析枸
        throw x; // 抛出 int类型 异常
    }

    cout << "divide y " << x / y << endl;

    return 0;
}

class Student {
public:
    explicit Student(int &&studentAge) {
        if (studentAge > 250) {
            throw out_of_range("age is too big.");
        }
        cout << "construct student" << endl;
        age = studentAge;
    }

    ~Student() {
        cout << "destruct student" << endl;
     }

private:
    unsigned int age{};
};

/*
 * 从标准异常类中进行继承
 * */
class MyException : exception {
public:
    explicit MyException(const char *p) {
        this->m_p = p;
    }
    ~MyException() override = default;
    virtual const char* what() {
        cout << "MyException " <<  m_p << endl;
        return m_p;
    }

private:
    const char *m_p{};
};

void TestMyException() {
    throw MyException("func exception");
}

/*
 *  构造函数中没有返回值,也通常需要通过异常来处理构造函数中的异常
 * */

int main(int argc, char*argv[]) {

    try {
        // 1.将可能引起异常的代码放到try的地方
        divide_demo(10, 2);
        divide_demo(10, 0);
    }
    catch (int e) {
        cout << "after throw" << endl;
        cout <<  "e = " << e << endl;
    } // ... 是其他未知类型的异常
    catch (...) {

    }

    /*
     *  使用标准异常
     * */
    try {
        Student student(300);
    }
    catch (out_of_range &eOut) {
        cout <<  eOut.what() << endl;
    }

    try {
        TestMyException();
    }
    catch (MyException &exceptData) {
        exceptData.what();
    }
    catch (...) {
        cout << "unknow  error" << endl;
    }

    return 0;
}

在这里插入图片描述

相关推荐
©️2020 CSDN 皮肤主题: 技术黑板 设计师:CSDN官方博客 返回首页
实付 9.90元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值