学习C++:异常处理

网友投稿 758 2022-05-29

1.导致异常的原因

异常可能是外部因素导致的,如系统没有足够的内存;也可能是应用程序内部因素导致的,如使用的指针包含无效值或除数为零。为向调用者指出错误,有些模块引发异常。

异常会打断应用程序的正常流程。毕竟,如果没有内存可用,应用程序就无法完成分配给它的任务。然而应用程序可处理这种异常:向用户显示一条友好的错误消息,采取必要的挽救措施并妥善地退出。

2.使用try和catch捕获异常

要捕获语句可能引发的异常,可将它们放在try块中,并使用catch块对try块可能引发的异常进行处理,语法如下:

void Func() { try { int* pNumber = new int; *pNumber = 999; delete pNumber; } catch(...) { cout<<"Exception in Func, quiting"<

1

2

3

4

5

6

7

8

9

10

11

12

13

(1)使用catch(…)处理所有异常

成功分配内存时,默认形式的new返回一个指向该内存单元的有效指针,但失败时引发异常。下面将演示如何捕获使用new分配内存时可能引发的异常,并在计算机不能分配请求的内存时进行处理。

#include using namespace std; int main() { cout<<"输入要存储的整数的个数:"; try { int Input = 0; cin>>Input; int* pRInts = new int [Input]; //自动分配内存空间 delete[] pRInts; } catch(...) //...捕获所有类型的异常 { cout<<"Got to end, sorry!"<

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

在此程序中,如果键盘输入的Input为一个负数,这显然不符合要求。如果没有异常处理,该程序将以讨厌你的方式终止。但由于有异常处理程序,程序将显示一条友好的消息:Got to end, sorry!结束程序。

(2)捕获特定类型的异常

一般的异常的类型是已知的,为了查明导致异常的原因,执行更有针对性的清理工作,或者至少是向用户显示一条提示消息,这时就可以选择捕获这种类型的异常。

其实上面(1)中的程序,当键盘输入指定存储的个数为负数时,将导致引发异常,而该异常类型为std::bad_alloc。

下面程序将演示捕获std::bad_alloc类型的异常:

#include #include using namespace std; int main() { cout<<"输入要存储的整数的个数:"; try { int Input = 0; cin>>Input; int* pRInts =new int [Input]; delete[] pRInts; } catch(std::bad_alloc& exp) //捕获类型为bad_alloc的异常,这种异常由new引发 { cout<<"Exception encountered: "<

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

3.使用throw引发特定类型的异常

在上面演示的程序中,捕获std::bad_alloc时,实际上是捕获new引发的std::bad_alloc类对象。你也可以引发自己选择的异常,为此只需要使用关键字throw。语法如下:

void Func()

{

if(case_unwanted)

throw Value;

}

当做除法运算时,若除数为0将导致程序异常。下面将演示如何使用throw引发这种自定义异常:

#include using namespace std; double Divide(double Dividend, double Divisor) { if (Divisor == 0) throw "Divisor should not be zero!"; return (Dividend / Divisor); } int main() { cout << "Enter Dividend: "; double Dividend = 0; cin >> Dividend; cout << "Enter Divisor: "; double Divisor = 0; cin >> Divisor; try { cout << "Dividend/Divisor=" << Divide(Dividend, Divisor); } catch(const char* exp) //捕获类型为char*的异常,于是可调用函数Divide()中可能引发的异常throw { cout << "Exception: " << exp << endl; cout << "Sorry, can't continue!" << endl; } return 0; }

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

注意:上述代码没有将整个main()都放在try{}中,而只在其中包含可能引发异常的代码。提倡这种做法,因为异常处理也可能降低代码的执行性能。

4.std::exception类

捕获std::bad_alllocl类型异常时,实际上是捕获new引发的std::bad_alloc对象。std::bad_alloc继承了C++标准类std::exception,而使用exception类时,需要添加头文件:#include

从std::exception派生出来的几个重要的异常类:

bad_alloc: 使用new请求内存失败时引发

bad_cast: 试图使用dynamic_cast转换错误类型时引发

ios_base::failure: 由iostream库中的函数和方法引发

std::exception是异常基类,定义了虚函数what(),用来描述导致异常的原因。

因为std::exception是众多异常类型的基类,所以所有将std::exception作为基类的异常,均可使用catch(const exception&)捕获:

void Func() { try { // code made exception safe } catch(const std::exception& exp) { cout<<"导致异常的原因是:"<

1

2

3

4

5

6

7

8

9

10

11

从std::exception派生出自定义异常类

让自定义异常继承std::exception的好处在于,现有的异常处理程序catch(const std::exception)不但能捕获bad_alloc、bad_cast等异常,还能捕获自定义异常,因为它们的基类都是exception。

下面将演示继承std::exception的CustomException类:

#include #include #include using namespace std; class CustomException : public std::exception { string Reason; public: CustomException(const char* why) :Reason(why) {} virtual const char* what() const throw() { return Reason.c_str(); } }; double Divide(double Dividend, double Divisor) { if (Divisor == 0) throw CustomException("CustomException: Divisor should not be zero!"); return (Dividend / Divisor); } int main() { double Dividend = 0, Divisor = 0; cout << "Enter Dividend: "; cin >> Dividend; cout << "Enter Divisor: "; cin >> Divisor; try { cout << "Dividend/Divisor=" << Divide(Dividend, Divisor); } catch (exception& exp) //不但处理异常CustomException,还处理bad_alloc等其他以exception为基类的异常 { cout << "导致异常的原因:"<

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

学习C++:异常处理

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

C++

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:GaussDB (DWS) 集群管理系列:实例进程异常重启告警
下一篇:Flutter 完美的验证码输入框(2 种方法)
相关文章