C++ 中的异常抛出和捕获方式

目录
  • C++ 中的异常
  • 语法
  • 抛出类型声明
  • 栈自旋

在 C 语言中,如果发生错误,上级函数要进行出错处理,层层上传,容易造成过多的出错处理代码,并且传递的效率比较低下。

C++ 中的异常

C++ 中,异常的引发和异常的处理不必处于同一个函数中,因此底层函数可以着重于解决具体问题,而不必过多的考虑异常处理

异常是专门针对抽象编程中的一系列错误处理的,遇到错误信息就转到若干级之上进行重新尝试

异常脱离于函数机制,决定了其对函数的跨越式回跳

语法

try
{
    statement;
}
catch(ExceptionType var)
{
    statement;
}

被检测的语句放在 try 块中

try catch 语句中的花括号是语法的一部分,不能省略

try-catch 结构中,只能有一个 try 块,catch 块可以有多个,以便与不同的类型信息匹配,有点类似于 switch-case 结构

利用 throw 抛出的异常类型,可以传递系统预定义的标准类型或自定义类型

从 throw 抛出异常,到 catch 捕获异常,有点类似与利用函数的返回值进行复制一样,因此如果使用了自定义类型,需要考虑自定义类型的赋值和拷贝问题

如果 catch 语句没有与之相匹配的异常类型信息,可以用(...)表示可以捕获任何异常类型的信息,有点类似与 switch-case 结构中的 default

try-catch 结构可以与 throw 在同一函数中,也可以不在同一个函数中,throw 抛出异常后,会先在本函数中寻找与之相匹配的 catch 块,如果没有与之相匹配的 catch,就可以转到上一层 try-catch,如果仍然没有

匹配到,则转到再上一层 try-catch...,如果最终到不到与之匹配的 try-catch 块,系统就会调用系统函数,terminal 使程序终止

#include <iostream>
 
using namespace std;
 
void func1()
{
    double a;
    try{
        throw a;
    }catch(double)
    {
        cout<<"catch func1()"<<endl; //throw
    }
    cout<<"end func1()"<<endl;
    return ;
}
 
void func2()
{
    try{
        func1();
    }catch(int)
    {
        cout<<"catch func2()"<<endl;
    }
    cout<<"end func2()"<<endl;
}
 
void func3()
{
    try{
        func2();
    }catch(char)
    {
        cout<<"catch func3()"<<endl;
    }
    cout<<"end func3()"<<endl;
}
 
int main()
{
    try{
        func3();
    }catch(double)
    {
        cout<<"catch main"<<endl;
    }
    cout<<"end main"<<endl;
    return 0;
}

结果为:

catch func1()
end func1()
end func2()
end func3()
end main

上边的异常传递路线为 func3->func2()->func1(),在 func1 中找到对应的 catch 块,然后执行对应 catch 块中的语句,输出:

catch func1()

整个的异常处理已经结束,跳出 func1() 的 try-catch 块,继续执行 func1() 的函数体,陆续输出:

end func1()
end func2()
end func3()
end main

此时进程结束。

如果将 func1() 中的 catch 到的异常类型换个类型,如:

catch(void *)

结果为:

catch main
end main

则会在 func1(),func2(),func3() 中都找不到对应的 catch 匹配,直到 main 函数才能找到对应的匹配,然后输出:

catch main
end main

如果将 main 函数中的 catch 捕获类型也修改为:

catch(void *)

结果为:

terminate called after throwing an instance of 'double'
 
This application has requested the Runtime to terminate it in an unusual way.
Please contact the application's support team for more information.

此时系统就会调用系统函数,使程序终止。

抛出类型声明

为了增强程序的可读性,可以在函数声明时就列出所有可能抛出的异常类型

void func() throw (A,B,C);     // 表明该函数只会抛出 A,B,C 及其子类型的异常

如果在函数声明时没有声明可能抛出的异常类型,则函数可以抛出任意类型的异常

不抛出任何类型异常的函数,可以声明为:

void func() throw();

如果一个函数抛出了抛出类型声明中所不允许的异常,unexpected 函数被调用,启用 terminal 函数中止程序

栈自旋

异常被抛出后,从进入 try 块起,到异常被抛掷前,这期间在栈上的构造的所有对象,都会被自动析构

析构的顺序与构造的顺序相反。这一过程称为栈的解旋

而堆上的空间,则会泄漏

#include <iostream>
 
using namespace std;
 
class A
{
public:
    A(){ cout<<"A()"<<endl; }
    ~A(){ cout<<"~A()"<<endl; }
};
 
int func1()
{
    A a;
    if(1)
        throw('a');
    return 0;
}
 
int func2()
{
    A b;
    func1();
    return 1;
}
 
int main()
{
    try{
        func2();
    }catch(int x){
        cout<<"x"<<endl;
    }catch(double y){
        cout<<"y"<<endl;
    }catch(...){
        cout<<"no x, no y"<<endl;
    }
    return 0;
}

结果为:

A()
A()
~A()
~A()
no x, no y

如果 throw 的是一个类对象:

#include <iostream>
 
using namespace std;
 
class A
{
public:
    A(){ cout<<"A()"<<endl; }
    A(const A &obj){ cout<<"A(const A &obj)"<<endl; }
    ~A(){ cout<<"~A()"<<endl; }
};
 
int func1()
{
    A a;
    if(1)
        throw(a);
    return 0;
}
 
int func2()
{
    func1();
    return 1;
}
 
int main()
{
    try{
        func2();
    }catch(int x){
        cout<<"x"<<endl;
    }catch(double y){
        cout<<"y"<<endl;
    }catch(const A &a){
        cout<<"no x, no y"<<endl;
    }
    return 0;
}

结果为:

A()
A(const A &obj)
~A()
no x, no y
~A()

以上为个人经验,希望能给大家一个参考,也希望大家多多支持我们。

(0)

相关推荐

  • C++异常捕捉与处理的深入讲解

    前言 在阅读别人开发的项目中,也许你会经常看到了多处使用异常的代码,也许你也很少遇见使用异常处理的代码.那在什么时候该使用异常,又在什么时候不该使用异常呢?在学习完异常基本概念和语法之后,后面会有讲解. (1)异常抛出和捕捉语句 //1.抛出异常 throw 异常对象 //2.异常捕捉 try{ 可能会发生异常的代码 }catch(异常对象){ 异常处理代码 } throw子句:throw 子句用于抛出异常,被抛出的异常可以是C++的内置类型(例如: throw int(1);),也可以是自定义

  • C++的异常处理一篇带你了解

    目录 一.背景 二.C++ 异常处理 三.抛出异常与捕获异常 四.catch(...)的作用 总结 一.背景 程序运行时常会碰到一些异常情况,例如: 做除法的时候除数为 0: 用 new 运算符动态分配空间时,空间不够导致无法分配: 访问数组元素时,下标越界:打开文件读取时,文件不存在. 这些异常情况,如果不能发现并加以处理,很可能会导致程序崩溃. 所谓"处理",可以是给出错误提示信息,然后让程序沿一条不会出错的路径继续执行:也可能是不得不结束程序,但在结束前做一些必要的工作,如将内存

  • C++中异常处理的基本思想及throw语句抛出异常的使用

    异常处理基本思想 C++的异常处理的基本思想大致可以概括为传统错误处理机制.通过函数返回值来处理错误. 1)C++的异常处理机制使得异常的引发和异常的处理不必在同一个函数中,这样底层的函数可以着重解决具体问题,而不必过多的考虑异常的处理.上层调用者可以再适当的位置设计对不同类型异常的处理. 2)异常是专门针对抽象编程中的一系列错误处理的,C++中不能借助函数机制,因为栈结构的本质是先进后出,依次访问,无法进行跳跃,但错误处理的特征却是遇到错误信息就想要转到若干级之上进行重新尝试,如图 3)异常超

  • C++抛出和接收异常的顺序

    异常(exception)是C++语言引入的错误处理机制.它 采用了统一的方式对程序的运行时错误进行处理,具有标准化.安全和高效的特点.C++为了实现异常处理,引入了三个关键字:try.throw.catch.异常由throw抛出,格式为throw[expression],由catch捕捉.Try语句块是可能抛出异常的语句块,它通常和一个或多个catch语句块连续出现. try语句块和catch语句块必须相互配合,以下三种情况都会导致编译错误: (1)只有try语句块而没有catch语句块,或者

  • C++ 中的异常抛出和捕获方式

    目录 C++ 中的异常 语法 抛出类型声明 栈自旋 在 C 语言中,如果发生错误,上级函数要进行出错处理,层层上传,容易造成过多的出错处理代码,并且传递的效率比较低下. C++ 中的异常 C++ 中,异常的引发和异常的处理不必处于同一个函数中,因此底层函数可以着重于解决具体问题,而不必过多的考虑异常处理 异常是专门针对抽象编程中的一系列错误处理的,遇到错误信息就转到若干级之上进行重新尝试 异常脱离于函数机制,决定了其对函数的跨越式回跳 语法 try {     statement; } catc

  • 简述Java中throw-throws异常抛出

    目录 一.throws抛出异常 Throws抛出异常的规则: 二.使用throw抛出异常 三.比较 3.1 在声明方法时候抛出异常 3.2 在方法中抛出异常 任何Java代码都可以抛出异常,如:自己编写的代码.来自Java开发环境包中代码,或者Java运行时系统.无论是谁,都可以通过Java的throw语句抛出异常.从方法中抛出的任何异常都必须使用throws子句. 一.throws抛出异常 如果一个方法可能会出现异常,但没有能力处理这种异常,可以在方法声明处用throws子句来声明抛出异常.例

  • JS中异常抛出和处理方法图文详解

    目录 抛出异常 抛出的表达式类型 基本数据类型 对象 类的实例对象 Error 类的实例对象 Error 的子类 处理异常 js中常见的系统异常: 总结 抛出异常 在 js 中,有时候我们需要处理一些异常或错误.比如编写的某个函数所接收的参数要求是 Number 类型的,如果在该函数被调用时传入的是字符串,就需要发出提醒.此时我们可以使用 throw 语句来抛出个异常: // 例 1 function fn(num) { if (typeof num !== 'number') throw '需

  • 窥探Swift编程中的错误处理与异常抛出

    在Swift 2.0版本中,Swift语言对其错误处理进行了新的设计,当然了,重新设计后的结果使得该错误处理系统用起来更爽.今天的主题就是系统的搞一下Swift中的错误处理,以及看一下Swift中是如何抛出异常的.在编译型语言中,错误一般分为编译错误和运行时错误.我们平时在代码中处理的错误为运行时错误,我们对异常进行处理的操作的目的是为了防止程序出现错误而导致其他的副作用,比如用户数据未保存等等. 在今天的文章中,先给出主动产生异常的几种情况,然后再给出如何处理被动异常. 一.主动退出程序的几种

  • Go语言错误处理异常捕获+异常抛出

    目录 一.error变量可以做什么 1.定义一个error变量 2.错误的处理 3.做函数返回值 4.做函数参数 二.模拟异常的捕获与抛出 1.defer简介 2.使用recover模拟异常的捕获 3.使用panic主动抛出错误 前言: Go 语言追求简洁优雅,所以,Go 语言不支持传统的 try…catch…finally 这种处理.Go 中引入的错误处理方式为:defer, panic, recover,也仅仅是错处处理的模拟Go语言的作者认为java等语言的错误处理底层实现较为复杂,就实现

  • java异常处理throws完成异常抛出详解

    已检查异常抛出 对于已检查异常(checked exceptions),编译器强制要求捕获并处理可能发生的异常,不处理就不能通过编译.但调用的方法没有能力处理这种异常,对于这种情况,可以在方法声明处使用throws子句来声明抛出异常,而是调用层次向上传递,谁调用这个方法,这个异常就由谁来处理.如:在service层读取文件,如果文件不存在,则需要将文件不存在的这条信息反馈给用户.要求在service层将此异常向上抛,用户层调用services层获取此条信息,反馈给用户.示例代码如下: 创建类Re

  • JAVA异常处理捕获与抛出原理解析

    JAVA 异常 当代码运行出现错误导致程序终止运行或出现错误情况的状况,就是异常.异常不是指语法错误,即不属于编译错误,只有运行的程序才会有异常. 这个时候,JAVA 就提供了优秀的处理方法:异常处理 异常处理能让程序在异常发生时,按照异常处理设定的逻辑对异常进行处理,最大程度保证程序继续运行,并且显示并处理异常. JAVA 程序发生异常,就会用对应的异常类的对象来封装异常,JRE(Java Runtime Environment) 便会寻找对应的异常处理逻辑来处理该异常. 总的说来,异常处理机

  • C++中的异常实例详解

    目录 1.异常 1.1C语言中处理错误的方式 1.2C语言处理错误方式的缺陷 2.C++异常 2.1异常相关关键字 2.2异常的使用 2.2.1异常的抛出和匹配原则 2.3异常的重新抛出 2.4自定义异常体系 2.5异常安全 2.6异常规范 2.7C++标准库的异常体系 2.8异常的优缺点 2.8.1优点 2.8.2缺点 总结 1. 异常 异常: 异常是面向对象与法处理错误的一种方式 1.1 C语言中处理错误的方式 返回错误码 (很多API接口都会把错误码放到errno当中) 终止程序 (ass

  • 浅谈java中异常抛出后代码是否会继续执行

    问题 今天遇到一个问题,在下面的代码中,当抛出运行时异常后,后面的代码还会执行吗,是否需要在异常后面加上return语句呢? public void add(int index, E element){ if(size >= elements.length) { throw new RuntimeException("顺序表已满,无法添加"); //return; //需要吗? } .... } 为了回答这个问题,我编写了几段代码测试了一下,结果如下: //代码1 public

  • springboot springmvc抛出全局异常的解决方法

    springboot中抛出异常,springboot自带的是springmvc框架,这个就不多说了. springmvc统一异常解决方法这里要说明的是.只是结合了springboot的使用而已.直接上代码,有效有用的才是ok. 1.定义异常捕获 package com.example.rest.error; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.Exce

随机推荐