C++编程异常处理中try和throw以及catch语句的用法
若要在C++中实现异常处理,你可以使用try、throw和catch表达式。
首先,使用try块将可能引发异常的一个或多个语句封闭起来。
throw表达式发出信号,异常条件(通常是错误)已在try块中发生。你可以使用任何类型的对象作为throw表达式的操作数。该对象一般用于传达有关错误的信息。大多数情况下,建议你使用std::exception类或标准库中定义的派生类之一。如果其中的类不合适,建议你从std::exception派生自己的异常类。
若要处理可能引发的异常,请在try块之后立即实现一个或多个catch块。每个catch块指定它能处理的异常类型。
以下示例将显示try块及其处理程序。假设GetNetworkResource()通过网络连接获取数据,并且两个异常类型是从std::exception派生的用户定义的类。请注意,异常由catch语句中的const引用捕获。我们建议你通过值引发异常并通过常数引用将其捕获。
MyDatamd; try{ //Codethatcouldthrowanexception md=GetNetworkResource(); } catch(constnetworkIOException&e){ //Codethatexecuteswhenanexceptionoftype //networkIOExceptionisthrowninthetryblock //... //Logerrormessageintheexceptionobject cerr<<e.what(); } catch(constmyDataFormatException&e){ //Codethathandlesanotherexceptiontype //... cerr<<e.what(); } //Thefollowingsyntaxshowsathrowexpression MyDataGetNetworkResource() { //... if(IOSuccess==false) thrownetworkIOException("Unabletoconnect"); //... if(readError) throwmyDataFormatException("Formaterror"); //... }
备注
try子句后的代码是代码的受保护部分。throw表达式将引发(即引起)异常。catch子句后的代码块是异常处理程序。如果throw和catch表达式中的类型兼容,该处理程序将捕获引发的异常。有关管理catch块中类型匹配的规则的列表,请参阅Catch块的计算方式(C++)。如果catch语句指定省略号(...)而非类型,catch块将处理每种类型的异常。当你使用/EHa选项编译时,异常可包括C结构化异常和系统生成或应用程序生成的异步异常,例如内存保护、被零除和浮点冲突。由于catch块按编程顺序处理以查找匹配类型,所以尽量不要使用省略号处理程序来处理关联的try块。请谨慎使用catch(...);除非catch块知道如何处理捕获的特定异常,否则禁止程序继续执行。catch(...)块一般用于在程序停止执行前记录错误和执行特殊的清理工作。
没有操作数的throw表达式将重新引发当前正在处理的异常。我们建议在重新引发异常时采用该形式,是因为这将保留原始异常的多态类型信息。此类表达式只应在catch处理程序中或从catch处理程序调用的函数中使用。重新引发的异常对象是原始异常对象,而不是副本。
try{ throwCSomeOtherException(); } catch(...){ //Catchallexceptions–dangerous!!! //Respond(perhapsonlypartially)totheexception,then //re-throwtopasstheexceptiontosomeotherhandler //... throw; }
Catch块的计算方式(C++)
虽然通常建议您引发派生自std::exception的类型,但C++使您能够引发任何类型的异常。可以通过指定与引发的异常相同的类型的catch处理程序或通过可捕获任何类型的异常的处理程序来捕获C++异常。
如果引发的异常的类型是类,它还具有基类(或类),则它可由接受异常类型的基类和对异常类型的基的引用的处理程序捕获。请注意,当异常由引用捕获时,会将其绑定到实际引发的异常对象;否则,它将为一个副本(与函数的参数大致相同)。
引发异常时,将由以下类型的catch处理程序捕获该异常:
- 可以接受任何类型的处理程序(使用省略号语法)。
- 接受与异常对象相同的类型的处理程序;由于它是副本,因此const和volatile修饰符将被忽略。
- 接受对与异常对象相同的类型的引用的处理程序。
- 接受对与异常对象相同的类型的const或volatile形式的引用的处理程序。
- 接受与异常对象相同的类型的基类的处理程序;由于它是副本,因此const和volatile修饰符将被忽略。基类的catch处理程序不得位于派生类的catch处理程序的前面。
- 接受对与异常对象相同的类型的基类的引用的处理程序。
- 接受与异常对象相同的类型的基类的const或volatile形式的引用的处理程序。
- 接受可通过标准指针转换规则将引发的指针对象转换为的指针的处理程序。
catch处理程序出现的顺序是有意义的,因为给定try块的处理程序按它们的出现顺序进行检查。例如,将基类的处理程序放置在派生类的处理程序的前面是错误的。找到一个匹配的catch处理程序后,不会检查后续处理程序。因此,省略号catch处理程序必须是其try块的最后一个处理程序。例如:
//... try { //... } catch(...) { //Handleexceptionhere. } //Error:thenexttwohandlersareneverexamined. catch(constchar*str) { cout<<"Caughtexception:"<<str<<endl; } catch(CExcptClassE) { //HandleCExcptClassexceptionhere. }
在此示例中,省略号catch处理程序是已检查的唯一处理程序。