开发 代码块不提示_Unix/Linux C++应用开发-异常以及错误处理

计算机应用程序中离不开错误处理,尤其是生产型大型软件系统。应用软件系统运行属于循环处理事务,出错后需要保证不能让软件程序直接退出。这就需要使用一定的程序容错处理来应对。一般情况下,大型软件开发中的软件系统容错处理会结合异常处理、错误代码定义的使用与相应的出错处理日志记录,包括一定的参与大型生产系统的监控系统等配合保障系统的稳定性。下面本章将会就C++软件系统中提供的异常处理作详细的讲述,包括基本概念以及应用操作情况。

afce0f15701ec38c19b5e52cd02b4287.png

一 、C++异常处理简介

软件应用程序中,异常处理机制是一种比较有效的处理系统运行时错误的方法。C++针对异常处理提供了一种标准的方法,用于处理软件程序运行时的错误,并用于处理软件系统中可预知或不可预知的问题。这样就可以保证软件系统运行的稳定性与健壮性。

C++中异常的处理主要用于针对程序在运行时刻出现错误而提供的语言层面的保护机制。它允许开发者最大限度地发挥,针对异常处理进行相应的修改调整。

C++应用程序中在考虑异常设计时,并不是所有的程序模块处理都需要附加上异常情况的处理。相对来说,异常处理没有普通方法函数调用速度快。过度的错误处理会影响应用程序运行的效率。通常在C++开发的软件系统中,应用程序都由对应的库、组件以及运行的具体不同模块组成。在设计时,异常的处理应充分考虑到独立程序库以及组件之间的情况。便于使用者在程序出现异常情况下,使用库或者组件的开发者能够快速定位出库、组件还是应用程序的错误。

由于大型软件系统中库与组件通常都是以独立的程序方式提供给具体设计开发模块人员。开发人员通常不了解组件与库中具体实现情况,只是根据提供的接口来操作使用。在不清楚具体库与组件的具体实现情况下,开发者可能在极端的情况下操作应用库或者组件提供的方法。此时相应的异常处理通信就会成为必不可少的错误处理通信机制。下面将会就C++语言提供的异常机制支持作详细应用讲述,在实践中总结异常应用的场合与具体实现方法。

二、C++异常处理方法

C++语言异常部分的支持也是在后续语言发展中逐步讨论并添加的内容。该语言针对异常处理提供了一系列的语法支持。C++语言除了提供异常的关键字语法支持以外,其标准库中支持异常处理而封装异常类也很好的为应用程序中异常处理判断使用提供直接的帮助。

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

C++语言中针对异常处理提供了三个关键字,分别为try、throw与catch。C++应用程序中通过这三个关键字实现机制组合来实现异常的处理。下面通过常见异常处理操作方式来介绍应用程序中使用异常处理关键字的基本方式,其基本语法定义如下所示。

try

{

… //可能出错产生异常的代码

throwtypen();

}catch(type1)

{

… //对应类型的异常处理代码

}catch(type2)

{

… //对应类型的异常处理代码

}

… //更多类型异常处理代码

或者

try

{

function();//调用可能会抛出异常的函数方法

}catch(type1)

{

… //对应类型的异常处理代码

}catch(type2)

{

… //对应类型的异常处理代码

}

C++应用程序中,try关键字后的代码块中通常放入可能出现异常的代码。随后的catch块则可以是一个或者多个;catch块主要用于异常对应类型的处理。try块中代码出现异常可能会对应多种异常处理情况,catch关键字后的圆括号中则包含着对应类型的参数。

try块中代码体作为应用程序遵循正常流程执行。一旦该代码体中出现异常操作,会根据操作的判断抛出对应的异常类型。随后逐步的遍历catch代码块,此步骤与switch控制结构有点相像。当遍历到对应类型catch块时,代码会跳转到对应的异常处理中执行。如果try块中代码没有抛出异常,则程序继续执行下去。

try体中可以直接抛出异常,或者在try体中调用的函数体中间接的抛出。下面将会通过一个简单的异常处理实例,来使用C++语言中支持的异常处理方式。

1.准备实例

打开UE工具,创建新的空文件,并且另存为chapter1401.cpp。该代码文件随后会同makefile文件一起通过FTP工具传输至Linux服务器端,客户端通过scrt工具访问操作。程序代码文件编辑如下所示。

/**

* 实例chapter1401

* 源文件chapter1401.cpp

* 简单异常处理

*/

#include

#include

using namespace std;

int main()

{

try

{

intvalue1,value2; //定义两个整型变量

cout<

cin>>value1>>value2; //从键盘输入两个整型数

cout<

if(value2== 0) //如果除数为0则抛出异常

{

throw0;

}

else //否则直接计算相除操作

{

cout<

}

}catch(inti) //捕捉参数为整型的异常

{

cout<

}

return0;

}

本实例程序主要通过try…catch方式来捕获异常,演示简单容错处理的一般实现方法。程序主要在main()函数内部定义实现,具体程序剖析见程序注释与后面讲解。

2.编辑makefile

Linux平台下需要编译源文件为chapter1401.cpp,相关makefile工程文件编译命令编辑如下所示。

OBJECTS=chapter1401.o

CC=g++

chapter1401: $(OBJECTS)

$(CC)$(OBJECTS) -g -o chapter1401

clean:

rm-f chapter1401 core $(OBJECTS)

submit:

cp-f -r chapter1401 ../bin

cp-f -r *.h ../include

上述makefile文件套用前面的模板格式,主要替换了代码文件、程序编译中间文件、可执行程序等。在编译命令部分-g选项的加入,表明程序编译同时加入了可调式信息。

3.编译运行程序

当前shell下执行make命令,生成可执行程序文件。随后,通过make submit命令提交程序文件至本实例bin目录。通过cd命令定位至实例bin目录,执行该程序文件运行,结果如下所示。

[developer@localhost src]$ make

g++ -c-o chapter1401.o chapter1401.cpp

g++ chapter1401.o -g -o chapter1401

[developer @localhost src]$ make submit

cp -f -r chapter1401 ../bin

cp -f -r *.h ../include

[developer @localhost src]$ cd ../bin

[developer @localhost bin]$ ./chapter1401

Please input two value:

12

0

Maybe exception code:

divisor is 0!

本实例中主要演示了除法中除数为0时抛出相应的异常,并作出对应的处理。本实例中try块中主要放置着可能出现异常的代码。该代码块中首先定义两个整型变量value1与value2。随后提示从键盘输入两个整型数,接着输出可能出现异常的提示信息。最后判断输入的除数value2是否为0。如果该判断条件成立,即程序执行中发生了除数为0的错误,则对应的代码体中使用throw抛出异常。如果判断条件不成立,则程序继续执行下去,

一旦符合抛出异常条件成立,则执行相应代码采用throw关键字抛出异常。此时关键字后跟着一个整型数0表示该异常。随后catch语句块捕捉异常,由于catch随后的参数类型符合抛出异常的类型匹配则执行catch中的异常处理,即打印输出除数为0的提示信息。在主程序中try块中抛出的异常的类型需要与随后的catch中参数类型一致,否则会程序将会异常终止。初学者可以将上述catch中参数类型修改为double类型测试看看当前编译器针对异常发生后匹配不到对应的catch时给出的反应。

如果try块中的代码没有抛出异常,则程序会直接忽略随后的catch块,直接执行后续的代码处理。在设计程序可能出现的异常处理时,将抛出异常的类型与对应的catch块中的类型规范的对应起来有助于程序在异常处理加入后更加清晰有条理。

2.2 throw抛出异常处理

C++程序中异常抛出是采用关键字throw实现的。通常throw关键字后会跟随着一个操作数,该操作数可以是一个表达式、一个C++内置类型数据或者为类类型的对象等。最常见的异常抛出都会放在try代码块中。当然,C++也允许抛出异常的地方在函数中供try块中的代码调用。正常情况下异常抛出点的定义不要放在try块外部无关的地方,因为那样通常会引起编译器默认的终止程序处理。最好的情况下,异常抛出点直接或者间接的定义在try块中。

try块中可以包含一个或者多个异常抛出点。但是需要注意的是,异常只要一抛出,对应的catch块捕捉到后,该try块中以下的代码体执行会被终止。代码执行直接进入对应的catch块中,最后catch块执行处理完异常后直接跳转至所有当前try块对应的catch块之后。

下面通过一个具体的实例来演示throw异常抛出的基本操作与需要注意的使用情况。

1.准备实例

打开UE工具,创建新的空文件并且另存为chapter1402.cpp。该代码文件随后会同makefile文件一起通过FTP工具传输至Linux服务器端,客户端通过scrt工具访问操作。程序代码文件编辑如下所示。

/**

* 实例chapter1402

* 源文件chapter1402.cpp

* 简单异常处理

*/

#include

#include

using namespace std;

void divideCompute(int value1,int value2) //除法计算函数定义

{

if(value1== 0) //如果被除数为0,则抛出参数类型为浮点型异常

{

throw0.0;

}

elseif(value2 == 0) //如果除数为0,则抛出参数类型为整型异常

{

throw0;

}

else //否则执行除法运算并打印输出结果

{

cout<

}

}

int main()

{

try

{

intvalue1,value2; //定义两个整型变量

cout<

cin>>value1>>value2; //输入两个整型数

cout<

divideCompute(value1,value2); //调用除法计算函数,传入两个输入的整型参数

}catch(inti) //捕捉整型参数异常

{

cout<

}catch(doublei) //捕捉浮点型参数异常

{

cout<

}

cout<

return0;

}

本实例通过throw关键字演示在函数内部抛出异常,程序调用处捕获异常并处理的场景。程序主要由函数divideCompute与主函数main组成,具体程序剖析见程序注释与后面讲解。

2.编辑makefile

Linux平台下需要编译源文件为chapter1402.cpp,相关makefile工程文件编译命令编辑如下所示。

OBJECTS=chapter1402.o

CC=g++

chapter1402: $(OBJECTS)

$(CC)$(OBJECTS) -g -o chapter1402

clean:

rm-f chapter1402 core $(OBJECTS)

submit:

cp-f -r chapter1402 ../bin

cp-f -r *.h ../include

上述makefile文件套用前面的模板格式,主要替换了代码文件、程序编译中间文件、可执行程序等。在编译命令部分-g选项的加入,表明程序编译同时加入了可调式信息。

3.编译运行程序

当前shell下执行make命令,生成可执行程序文件。随后通过make submit命令提交程序文件至本实例bin目录。通过cd命令定位至实例bin目录,执行该程序文件运行结果如下所示。

[developer@localhost src]$ make

g++ -c-o chapter1402.o chapter1402.cpp

g++ chapter1402.o -g -o chapter1402

[developer @localhost src]$ make submit

cp -f -r chapter1402 ../bin

cp -f -r *.h ../include

[developer @localhost src]$ cd ../bin

[developer @localhost bin]$ ./chapter1402

Please input two value:

0

0

Maybe exception code:

dividend is 0!

here!

本实例中主要设计了除法中可能出现的异常。此处抛出异常没有直接放在try代码块中,而是通过间接的方式放置在函数定义中,供try代码块中调用。此时除法操作定义的函数中包含着可能出现的两个异常抛出点。一类是针对被除数为0时,抛出浮点型参数异常。另一类则针对除数为0时,抛出整型参数异常。

整个主程序代码中catch主要有两个参数类型的捕获处理。分别对应着除数以及被除数为0时异常抛出捕获处理。上述实例表明try代码块中可以直接放置或者间接放置多个throw异常抛出点。一旦其中一个异常点抛出后程序控制权将会转移到对应的catch参数类型异常处理中。对应的异常处理完后将会意味着程序执行将会终止try异常块中的程序块。直接转移到对应的所有catch异常处理块之后的代码执行。

上述主程序中从try块中开始执行,try代码快中首先定义两个整型变量value1与value2。随后提示从键盘输入两个整型数,上述程序执行后输入两个整型数都为0。之后将输入的两个整型数作为除法计算函数的实参调用除法计算函数。根据传入的实参首先判断被除数为0则抛出浮点型参数异常,随后程序转移到对应catch块中执行异常处理,输出提示信息“dividend is 0!”。程序代码转移至catch处理块中之后,则退出了异常抛出的所在块。直接处理完毕后,转到所有catch块之后继续执行代码,即最后执行输出“here!”提示信息代码。

2.3 catch捕捉异常处理

catch关键字的代码块则主要负责异常的捕获处理,catch块可以拥有多个,并且紧跟着try块之后。每个catch块部分主要由圆括号中参数类型,紧跟其后的大括号中异常代码处理部分构成。前面小节在讲述异常抛出处理时已经对其使用的原理作过解释,即当在可能抛出异常的try代码块中通过throw抛出了异常。随后开始匹配catch块中的参数类型是否符合异常抛出时的类型,如果符合则执行对应catch块中的代码处理。

多个catch块中,遍历到对应的catch块则执行随后代码块处理异常。catch块中随后圆括号中参数类型,该类型可以拥有变量名称或者对象名称,也可以直接是对应的参数类型。如果是对应的类型对象,则在catch块中可以引用该对象处理。而如果是只有数据类型没有相应参数名称的参数,则直接匹配对应的参数类型即可,程序会从try块中转移至catch块中执行。

如果异常抛出了,匹配对应的catch块没有对应类型的异常处理时,则会调用默认的异常abort来终止程序的执行。catch块中的参数除了采用基本的内置类型、自定义类类型外,还可以使用三个点的省略号(即catch(…))来表示捕捉所有的异常。此时,当try块中一旦抛出异常时,如果对应的catch块中只有一个catch(…)或者对应的catch(…)放置在所有其它catch块最后。那么,异常发生时只会执行对应的catch(…)中的代码处理,或者当前面所有的catch都匹配不到时,则匹配catch(…)捕获所有异常处理。通常情况下捕捉所有异常的定义会放在所有其它catch块最后位置,这样的好处就是程序不会因为抛出异常匹配不到对应的catch块而终止。

上述实例代码作出如下修改,根据实例中添加catch(…)块观察捕捉异常处理情况。

1.准备实例

打开UE工具,创建新的空文件并且另存为chapter1403.cpp。该代码文件随后会同makefile文件一起通过FTP工具传输至Linux服务器端,客户端通过scrt工具访问操作。程序代码文件编辑如下所示。

/**

* 实例chapter1403

* 源文件chapter1403.cpp

* 捕获所有异常处理

*/

#include

#include

using namespace std;

void divideCompute(int value1,int value2) //除法计算函数定义

{

if(value2== 0) //如果除数为0,则抛出相应的整型异常

{

throw0;

}

else //否则计算除法运算,并打印结果

{

cout<

}

}

int main()

{

try

{

intvalue1,value2; //定义两个整型变量

cout<

cin>>value1>>value2; //从键盘输入两个整型值

cout<

divideCompute(value1,value2); //调用除法计算函数

}catch(doublei) //对应浮点型参数异常处理

{

cout<

}catch(inti) //对应整型参数异常处理

{

cout<

}catch(...) //捕获所有异常处理

{

cout<

}

cout<

return0;

}

本实例主要通过catch(…)方式使用演示在异常处理相关类型捕获不到的情况下,异常的默认处理情况。程序主要由函数divideCompute()与主函数main()组成,程序具体剖析见程序注释与后面程序讲解。

2.编辑makefile

Linux平台下需要编译源文件为chapter1403.cpp,相关makefile工程文件编译命令编辑如下所示。

OBJECTS=chapter1403.o

CC=g++

chapter1403: $(OBJECTS)

$(CC)$(OBJECTS) -g -o chapter1403

clean:

rm-f chapter1403 core $(OBJECTS)

submit:

cp-f -r chapter1403 ../bin

cp-f -r *.h ../include

上述makefile文件套用前面的模板格式,主要替换了代码文件、程序编译中间文件、可执行程序等。在编译命令部分-g选项的加入,表明程序编译同时加入了可调式信息。

3.编译运行程序

当前shell下执行make命令,生成可执行程序文件,随后通过make submit命令提交程序文件至本实例bin目录,通过cd命令定位至实例bin目录,执行该程序文件运行结果如下所示。

[developer@localhost src]$ make

g++ -c-o chapter1403.o chapter1403.cpp

g++ chapter1403.o -g -o chapter1403

[developer @localhost src]$ make submit

cp -f -r chapter1403 ../bin

cp -f -r *.h ../include

[developer @localhost src]$ cd ../bin

[developer @localhost bin]$ ./chapter1403

Please input two value:

1

0

Maybe exception code:

divisor is 0!

here!

上述实例中,主程序中根据输入的实参整型数调用除法计算函数。在除法计算函数中,一旦除数为0,则抛出整型参数为0的异常。此时开始匹配try块对应后的catch块中的参数类型。首先对比第一个catch块,由于其参数类型为double类型不符合类型匹配,则继续向下搜索。try块后的第二个捕捉异常处理catch块中的参数类型为整型,并且该参数还拥有参数类型对应变量。匹配到该catch块后,程序转移到对应的代码块中处理,该代码块中主要用于打印输出说明除数为0,此时则直接引用了参数类型后的变量名。

主程序中上述匹配到的catch块执行完之后直接转移至所有catch块之后继续执行。执行最后打印输出语句。此时如果前面几个catch都没有匹配对应的参数类型时,则catch(…)块中异常处理代码会被执行,初学者可以自行修改程序进行测试学习。

2.4 throw重抛异常处理

重新抛出异常通常应用在try嵌套层中。最常见的应用即当前try块中捕捉异常块不作任何处理时,可以通过重抛异常让try层外部的catch块来处理。如果try层外部已经没有对应的try与catch块处理,则会调用默认的异常处理终止程序。下面将会通过一个完整实例来演示异常重抛的应用情况。

1.准备实例

打开UE工具,创建新的空文件并且另存为chapter1404.cpp。该代码文件随后会同makefile文件一起通过FTP工具传输至Linux服务器端,客户端通过scrt工具访问操作。程序代码文件编辑如下所示。

/**

* 实例chapter1404

* 源文件chapter1404.cpp

* throw重抛异常处理

*/

#include

#include

using namespace std;

void divideCompute(int value1,int value2)

{

try

{

if(value2== 0) //如果除数为0,则抛出异常

{

throw0; //抛出整型异常

}

else //否则计算除法运算

{

cout<

}

}catch(doublei) //捕捉浮点型参数异常

{

cout<

}catch(inti) //捕捉整型参数异常

{

cout<

throw; //重抛异常

}catch(...) //捕捉所有类型异常

{

cout<

}

}

int main()

{

try

{

intvalue1,value2; //定义两个整型变量

cout<

cin>>value1>>value2; //输入两个整型变量

cout<

divideCompute(value1,value2); //调用除法计算函数

}catch(doublei) //外层捕捉浮点型异常

{

cout<

}catch(inti) //外层捕捉整型异常

{

cout<

}catch(...) //外层捕捉所有类型异常

{

cout<

}

cout<

return0;

}

本实例程序主要演示try…catch嵌套使用中,通过throw关键字重新抛出异常的功能。程序主要由函数divideCompute与主函数组成,程序具体剖析见程序注释与后面讲解。

2.编辑makefile

Linux平台下需要编译源文件为chapter1404.cpp,相关makefile工程文件编译命令编辑如下所示。

OBJECTS=chapter1404.o

CC=g++

chapter1404: $(OBJECTS)

$(CC)$(OBJECTS) -g -o chapter1404

clean:

rm-f chapter1404 core $(OBJECTS)

submit:

cp-f -r chapter1404 ../bin

cp-f -r *.h ../include

上述makefile文件套用前面的模板格式,主要替换了代码文件、程序编译中间文件、可执行程序等。在编译命令部分-g选项的加入,表明程序编译同时加入了可调式信息。

3.编译运行程序

当前shell下执行make命令,生成可执行程序文件。随后通过make submit命令提交程序文件至本实例bin目录。通过cd命令定位至实例bin目录,执行该程序文件运行结果如下所示。

[developer@localhost src]$ make

g++ -c -o chapter1404.o chapter1404.cpp

g++ chapter1404.o -g -o chapter1404

[developer@localhost src]$ make submit

cp -f -r chapter1404 ../bin

cp -f -r *.h ../include

[developer@localhost src]$ cd ../bin

[developer@localhost bin]$ ./chapter1404

Please input two value:

1

0

Maybe exception code:

rethrow exception:

divisor is 0!

here!

本实例中主要演示了try块中调用除法计算方法。该方法中又存在try与catch块的嵌套处理情况。上述实例主程序中同样是定义两个整型变量value1与value2,随后从键盘输入两个整型数作为实参调用除法计算函数。除法计算函数中仍然包含着try块,try块中包含着可能抛出异常的代码。一旦输入的实参中除数为0则报出整型类型的异常,被随后的catch整型参数块所捕获执行相对应的异常处理代码。

在对应的异常处理catch块中允许针对异常不作出任何的处理,而直接使用throw不带任何的参数类型重新抛出异常,交由外层的catch块来捕获。此时代码执行被转移至外层catch块进行匹配。如果匹配到整型类型的异常处理时,则进入执行相应的异常处理。如果没有匹配到则执行catch(…)块捕获所有异常,随后转移至catch块外继续执行。

上述实例程序执行时传入两个整型数1和0。由于除数为0则在除法函数体中try块抛出异常。此时最内一层catch开始进行捕获匹配,匹配到整型参数类型异常处理则进入执行。最内层的catch整型参数中除了打印输出提示重抛异常信息外,则执行throw重抛异常。被外层对应的catch块捕获进入执行相应异常处理,通过直接引用捕获异常参数类型的变量打印除数为0的信息提示。

三、小结

C++异常处理的提出为编写出更具健壮性、稳定性的应用程序提供了很好的支持。但是异常与前面介绍该语言的特性一样,不能够滥用。因为任何支持的特性总是以牺牲一定的效率来实现的。通过上述介绍,用户在实际软件系统中可以结合错误处理、异常以及对应的错误日志等,最终开发出高稳定、高容错性的应用系统。由于篇幅有限,未完待更。。。

注:需要C/C++ Linux服务器开发学习资料私信“资料”(资料包括C/C++,Linux,golang技术,Nginx,ZeroMQ,MySQL,Redis,fastdfs,MongoDB,ZK,流媒体,CDN,P2P,K8S,Docker,TCP/IP,协程,DPDK等),免费分享

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值