首页 > 编程语言 >C++异常处理:try、throw、catch

C++异常处理:try、throw、catch

时间:2023-08-24 23:34:15浏览次数:36  
标签:抛出 C++ try Error catch 异常 throw

​1.引子

程序在运行时,总是会遇到一些错误,这些错误或者是导致程序无法运行,例如操作空指针,或是不符合正常运行的规律,例如除以0。

因此,在C++程序当中就必须添加对应异常处理机制,在检测到指定的程序异常时,为保证程序正常运行,需要跳转至异常处理程序当中。

常规的错误处理有以下几种解决方案:

2.abort()

在遇到错误时,可以调用abort函数

abort函数位于标准库的头文件cstdlib当中,它会向标准错误流发送一个程序异常终止消息,然后终止程序。

int main() {
    abort();
    return 0;
}

当然,这种方式实际上并不灵活,abort的调用会直接终止程序,并不是我们所想要的结果。通常我们都会建立故障诊断机制,所以abort的使用频率比较低。

3.try throw catch

C++自带有异常处理机制,提供了将控制权从程序的一个部分转移到另一个部分的途径,这种对异常的处理方法包含三部分:

try:标识其中特定的异常可能被激活的代码块。

throw:当出现异常时抛出异常,跳转至处理部分。

catch:捕获异常,针对不同的异常类型采取对应的措施

基本写法为:

try{
    //Error e("error!");
    //throw e;
    throw 1;
    //throw 1.5;
    //throw Error ("error!");
}
catch (double){

}
catch (int){

}
catch (Error& e){

}

其中,抛出异常和捕获异常有多种写法,可以适用于不同的情况。

3.1.抛出异常

异常抛出有以下几种写法:

直接抛出数值,会根据值的类型自动做隐式转换,例如int和double,这种用法弊端比较大,一般不怎么使用:

throw 1;    // 相当于throw (int)1;
throw 1.5;     // 相当于throw (double)1.5;

构造并抛出异常值,如果异常被封装为类,则会用构造函数对异常进行构造。当然也可以先构造一个类出来,然后将这个类抛出,两种做法是一样的。

class Error{
    public:
        Error(const char* message) 
            : m_message(message)
        { };
private:
        string m_message;
};

throw Error("error!");    // 1.调用构造函数后抛出

Error e("error!");
throw e;    // 2.抛出构造后的值

3.2.捕获异常

异常捕获有以下几种写法:

类型捕获,依据throw抛出的类型进行选择最终进入哪一个catch模块,多个catch连成一片类似于else if,只不过catch检测的是类型。如果没有抛出异常,那么不会进入任何一个catch块当中。

catch (int){ 
}
catch (double){ 
}
catch (Error){ 
}

类型+返回值捕获,返回的不只是类型,实际上还隐藏了返回值,可以自定义返回值的名称将其显式表示,并将其运用到catch模块当中。

catch (Error& error){ 
 cout << error << endl;
}

捕获其它异常,"..."这种写法相当于else,任何其它类型的异常都会被该catch捕获。

同理,如果没有写catch(...)就相当于没有写else,那么当程序因为异常抛出,但是没有找到对应类型的异常时,则不会执行任何catch内的操作。

catch (...){
}

3.3.嵌套

多个异常模块可以嵌套使用,但在任意位置抛出异常时,程序会逐级选择catch模块,直到找到对应的catch块或者跳出所有嵌套的try块为止,中间其它try当中的内容,都会被忽略。

例如下面的程序:

输出double异常时,跳转至catch(double)中,继续运行外层try当中的内容,从而输出1、2、3、4、6;

输出int异常时,跳转至catch(int)中,无视了外层try块剩下的内容,从而输出1、2、5 2、6;

int main() {

    try {
        std::cout << "1..." << endl;
        try {
            std::cout << "2..." << endl;
            //double error = 2;    //如果抛出double,则输出1、2、3、4、6
            int error = 2;    //如果抛出int,则输出1、2、5 2、6
            throw error;    
        }
        catch (double ) {
            std::cout << "3..." << endl;
        }
        std::cout << "4..." << endl;
    }
    catch (int& error) {
        std::cout << "5..." << error << endl;
    }
    std::cout << "6..." << error << endl;
    return 0;
}

4.故障码

虽然这一节主要讲的是try throw catch,但实际上这种异常解决方案用的还是不算多,最常使用的依然是故障码。

故障码不是啥新鲜的东西,设置一个全局或较高层级的故障类,用以记录故障的类型。在每个程序模块运行时对故障进行检测,同时在运行过程中出现异常时对故障进行对应的填充。

在C语言当中,只能用结构体指针的方式进行传输,不够方便,而C++以类的形式进行封装更有利于这种方式的异常处理。

其伪代码如下所示:

Error e;

if(e == null){
    ...
    if(){
        e = error;
    }
}
...

故障码有个优势,那就是相比于try catch的结构,可以比较容易地对程序进行控制,对于异常的处理更加的精细化,因此很多时候用的比较多的反而是这种解决方案。

标签:抛出,C++,try,Error,catch,异常,throw
From: https://www.cnblogs.com/wyqmx/p/17655461.html

相关文章

  • C++静态成员(static)
    静态成员(static)什么是静态成员:被static修饰的成员/成员函数就叫静态成员,不管有多少对象,静态成员只有一份存于公共内存中。设计静态数据成员目的是信息共享和信息交流普通成员特点:成员变量:每个类对象中都有一份属于自己的成员变量,相互独立、没有关联。普通成员与对象绑定,随......
  • C++11 四种强制类型转换的区别
    static_cast:指针强转,如果某个基类有多个子类,基类的指针实际是指向A类的对象,但使用强转为B类对象,运行时会报错,静态强转没做检测dynamic_cast:只能用于虚函数类,子类与父类指针互转,会检测,转换失败为返回空,不会崩const_cast:用于转换常量,修改常量,先用一个常......
  • C++拷贝构造、赋值函数
    拷贝构造拷贝构造就是一种特殊版本的构造函数,格式:类名(const类名&that){    //执行给每个成员变量进行赋值  }什么时候会调用拷贝构造:当使用旧对象(已new的)给新对象(新new的)初始化时,会自动调用拷贝构造    Testt1;//调用无参构造Testt2=t1......
  • C++this指针、常函数
    this指针this指针的类型:类类型*const。不能被修改和赋值。只能在成员函数的内部使用。全局函数、静态函数都不能使用this.this指针本质上其实是一个成员函数的形参(栈),是对象调用成员函数时,将对象地址作为实参传递给this形参。所以对象中不存储this指针。this指针是成......
  • C++静态成员和单例模式
    一、静态成员Ⅰ.什么是静态成员:被static修饰的成员变量和成员函数就叫静态成员Ⅱ.普通成员的特点:成员变量:每个类对象中都有一份属于自己的成员变量,相互之间没有关联、独立的成员函数:隐藏着一个this指针,接收调用者的地址用于区分调用者Ⅲ.静态成员的特点:静态成员变......
  • C++对象的创建和销毁过程分析
    对象的创建和销毁过程分析1、对象的创建过程①给对象划分内存空间(栈、堆)②执行初始化列表根据继承表的顺序调用父类的无参构造或有参构造通过:父类(val)调用父类的有参构造根据成员变量的定义顺序调用类类型成员的无参构造或有参构造通过:类类型成员名(val)调用类类型成员......
  • C++面向对象、类和对象、访问控制限定符
    面向对象和面向过程面向过程:关注如何解决问题,以及解决问题的步骤面向对象:关注的解决问题的"人"即"对象",以及实现能解决问题的"对象"注意:面向对象的细节的本质上还是面向过程,因此面向对象不是解决问题的捷径,而是以更高的维度去思考问题面向对象的四个特性:抽象:先找出(想象)......
  • Windows中通过C++自动添加防火墙例外规则
    在C++程序中无法直接控制防火墙警报窗口的显示,因为这是由操作系统和防火墙软件控制的。防火墙警报窗口是为了提醒用户程序正在尝试与外部网络进行通信,以确保用户意识到可能的网络活动。然而,可以通过编写C++程序在用户的系统上自动添加防火墙例外规则,从而避免防火墙警报窗口的显示......
  • ChatGPT 问答00022 Guava Retryer使用
    使用GuavaRetryer进行方法异常重试的步骤如下:添加GuavaRetryer依赖:在项目的构建文件(如pom.xml)中添加以下依赖项:<dependency><groupId>com.github.rholder</groupId><artifactId>guava-retrying</artifactId><version>2.0.0</version></de......
  • C++构造函数、析构函数、初始化列表
    构造函数构造函数就是与类名同名的成员函数,当实例化对象时它会自动执行,当构造函数执行结束后,对象才完成实例化任务:一般负责对类对象进行初始化、资源分配class类名{int*p;public:类名(参数){p=newint;}}......