【翻译】MSDN:异常处理

来源:互联网 发布:mysql慢查询日志 编辑:程序博客网 时间:2024/06/06 09:13

正好用到这部分,就随便翻译了一下,翻得不好,并且没翻完,以后会补上,看到这篇东东的人不要笑我

异常处理:概述

 

异常一般在出现程序控制之外的状况时发生,如内存不足或者I/O错误,引起的程序执行不正常的时候。不正常的状况应该做抛出或者捕获异常处理。不正常的状况跟一般的错误状况(如函数执行错误但是返回的结果代码标识了一个错误)不同。例如,文件状态函数识别一个文件不存在就是一个普通的错误状况。对普通错误状况来说,检测错误代码并作出适当的响应即可。不正常的状况也跟错误的执行(例如,调用者在给函数传入参数时犯错或者在不适合的环境中调用函数)不同。对错误的执行错误来说,用assert检测输入的参数或其他可能出现问题的变量就可以。

VC++支持三种类型的异常处理:

.C++ exceptions

.Structured exception handling (SEH), used in C programs for Windows NT and Windows 95

.MFC exceptions

注意:自3.0版本依赖,MFC开始使用C++ Exception,但是仍然支持它那些老版本的异常处理宏。

使用建议
在MFC程序中,要使用C++ EXCEPTION;不要使用SEH。只在非MFC程序中使用SEH。不要把这两种方法混在一块。

What do you want to know more about?

  • 什么时候选用哪种异常处理机制

  • C++ exceptions, the exception mechanism that is part of the C++ language

  • C++ exception handling: Synchronous exception model is now the default

  • Structured exception handling

  • Exception handling in an MFC program

  • The exception classes used in MFC database programming

  • The exception classes used in MFC OLE programming

  • Converting from the older MFC exception macros to C++ exceptions


什么时候选用哪种异常处理机制


VC++支持三种不同的错误处理机制。可以根据自己的情况选择其中的一种。

.C++ exceptions
在VC++,MFC中

.结构化异常处理 SEH
WIN NT提供自己的异常机制,称作结构化异常处理(SEH)。SEH不被推荐在C++或MFC编程中使用、

.MFC异常处理宏
自MFC 1.0版本以来,MFC就支持通过一系列宏来处理异常的机制。尽管在新的编程中不推荐使用这些宏,但是这些宏依然被支持向后兼容。在已经使用了宏的程序中,你也可以自由的使用C++ Exception。在预处理过程中,从VC++ 2.0版本以来,这些宏被认为是C++语言的VC++工具中定义的异常处理关键字。当你开始用c++ exceptions的时候,你可以不用管已经存在那些异常处理宏。


c++ exception

这个异常机制是C++语言的一部分
C++语言为处理异常情况,也就是程序执行过程中会发生的异常(),提供了内建的支持。利用C++异常处理程序可以把意外的事件传递到更高层的执行环境中,在这个环境中能更好的把那些不正常事件中恢复正常。这些异常会被常规控制流向的外面的代码里处理掉。

注意 在这些文章中,名词“结构化的异常处理”与“结构化异常”(或者叫C异常)仅仅指WINDOWS 95和NT提供的 WIN32 结构化异常处理机制。关于其他的异常处理(或者称为C++异常)是指C++异常处理机制。

注意 MFC现在使用 C++ 异常处理。老版本的MFC异处理宏,如果你还在使用它们,等同于C++ 异常关键字。不像WIN32 结构化异常处理机制,语言自身提供了对C++异常处理的支持。对C++编程来说,你更应该使用C++异常处理,而不是使用SEH。在C++程序中使用SEH,比使用C++异常处理,更能保证代码的可移植性。C++异常处理机制更灵活,使用它可以处理任何类型的异常。C的异常只有UNSIGNED INT类型。

.C++异常的使用

在C++中,引起异常的处理被称作抛出一个异常。接着一个指定的异常处理抓住这个被抛出的异常。为了能在你的代码中使用异常处理,在VC++ Studio中打开 “工程”设置对话框,选择"c/c++"标签,在类别框中选择 "C++ Language",并且选中 "Enable Exception Handling";或者使用 "/GX" 编译选项。默认为 "/GX-",它禁止异常处理。

注意 从4.0版本以来,MFC(包括VC++)就开始使用C++异常处理机制。尽管鼓励在新代码中使用C++异常处理。MFC 4.0版本和后来的版本都从保留了以前的版本中的宏,以使老的代码不会被破坏。宏和新的机制可以被很好的合并在一起。For information on mixing macros and C++ exception handling and onconverting old code to use the new mechanism, see the articles Exceptions: Macros and C++Exceptions, and Exceptions: Converting from MFC Exception Macros.



.Exception handling syntax 异常处理语法


C++异常处理的语法结构被表达如下:
try-block :
try compound-statement handler-list

handler-list :
handler handler-listopt

handler :
catch ( exception-declaration ) compound-statement

exception-declaration :
type-specifier-list declarator
type-specifier-list abstract-declarator
type-specifier-list
...

throw-expression :
throw assignment-expressionopt

try后面的代码组合是被监视的代码。“throw-expression”抛出一个异常。catch后面的代码组合示是异常处理,并且捕获被throw-expression抛出的异常。catch后面的exception-declaration语句识别处理的异常的类型。这些类型可以是任何有效的类型,包括C++类。 如果异常声明部分是(...),catch部分就是处理任何一种异常,包括系统产生的和程序产生的C异常。这些异常包括内存包括,被0除,浮点侵犯(??)。省略号的捕获处理对try部分来说一定要是最后一个处理。
throw的操作从句法上跟return很相似。

Microsoft Specific —>
微软C++不支持函数异常规范机制。
END Microsoft Specific

.Exception handling: default synchronous exception model

在VC++以前的版本中,C++异常处理机制缺省的支持异步(硬件)异常。在异步模型下,编译器架设任何命令都可以产生异常。
在新的同步异常模型下,现在默认的异常可以只通过throw来抛出。一次,编译器可以假设只有在throw的时候或者在函数调用的时候异常会发生。如果对象的生命周期没有与函数调用或者throw语句重叠,这个模型允许编译器去掉对当前展开对象的生命周期的追踪,并且可以相当大程度上的较少代码的大小。这两个异常处理模型,同步与异步,是完全兼容并且可以在一个应用中混合使用的。 使用同步模型捕获硬件异常也是有可能的。然而,如果编译器判定对同步模型来说不需要追踪这些展开对象的生命周期,那么这些函数中的展开对象可能会由于发生异常而未展开。

.Type-safe exception handling 类型安全的异常处理


C++异常处理支持类型安全异常处理。C异常总是被认为是一个unsigned int.使用c++异常处理,你可以指定一个特定类型的异常(包括c++对象)被一个符合被抛出异常类型的处理器捕获。

.C++ exception examples


C++异常处理的真正能力不仅表现在它处理各种类型的异常的能力上,还表现在他能在退栈时自动调用所用在异常被抛出前构造的所有本地对象的析构函数。throw与catch之间存在的上下文环境被称为“异常栈帧”。这个帧包含带有析构语法的对象。如果一个异常在监视部分的执行过程中或者被监视部分的常规调用中(直接或间接的)被抛出,一个异常对象就会在被throw操作数创建的对象处被创建(暗指一个复制构造函数被调用)。在这里,编译器在上一层能处理这种类型的抛出异常的执行环境中查找catch字句,或者查找能处理任何类型异常的catch处理程序。按照catch处理程序在try区块后面的顺序被检测。如果没有发现合适处理程序,就会检查上一层try区块,直到最外面的try区块被检测。如果依然没发现合适的处理程序,或者当在一个处理程序处理以前有异常发生,预先定义的运行时函数terminate就会被调用。 如果在抛出异常后有一个异常发生但是还没开始展开(unwind可理解为展开,开始执行),terminate函数被调用。你可以为处理某些状况定制终止函数。

下面的例子示范了使用带有析构语法的类的c++异常处理。
#include <iostream.h>

void MyFunc( void );

class CTest
{
public:
CTest(){};
~CTest(){};
const char *ShowReason() const { return "Exception in CTest class."; }

};

class CDtorDemo
{
public:
CDtorDemo();
~CDtorDemo();
};

CDtorDemo::CDtorDemo()
{
cout << "Constructing CDtorDemo." << endl;
}

CDtorDemo::~CDtorDemo()
{
cout << "Destructing CDtorDemo." << endl;
}

void MyFunc()
{

CDtorDemo D;
cout<< "In MyFunc(). Throwing CTest exception." << endl;
throw CTest();
}

int main()
{
cout << "In main." << endl;
try
{
cout << "In try block, calling MyFunc()." << endl;
MyFunc();
}
catch( CTest E )
{
cout << "In catch handler." << endl;
cout << "Caught CTest exception type: ";
cout << E.ShowReason() << endl;
}
catch( char *str )
{
cout << "Caught some other exception: " << str << endl;
}
cout << "Back in main. Execution resumes here." << endl;
return 0;

}

 

.Unhandled exceptions


如果一个异常没有发现一个合适的捕获处理程序,预先定义的 terminate 运行时函数就会被调用。(你可以在你的任何处理程序中显式的调用terminate)。terminate的默认动作就是调用aboirt。如果你想terminate调用程序中其他的函数,调用 set_terminate函数,把那个函数的名字和它的一个变量当作参数。你可以在你程序的任何地方调用 set_terminate.terminate通常调用最后一次给set_terminate做参数的的函数。


#include <eh.h> // For function prototypes
#include <iostream.h>
#include <process.h>

void term_func()
{
//...
cout << "term_func was called by terminate." << endl;
exit( -1 );
}
int main()
{
try
{
// ...
set_terminate( term_func );
// ...
throw "Out of memory!"; // No catch handler for this exception
}
catch( int )
{
cout << "Integer exception raised." << endl;
}
return 0;
}

 

.Order of handlers

.Mixing C and C++ exceptions


如果你想写出移植性更好的程序,不推荐你在C++程序中使用SEH。不过,有时候,你想把c与c++代码混在一起,需要一种灵活的手段来处理这两种异常。因为seh异常处理没有对象或者类型的概念,他不能处理被c++代码抛出的异常;然后,c++捕获处理程序可以处理c异常。从这方面说,c++异常处理语法(try,throw,cath)不会被c编译器接收,但是SEH语法(__try,__except,__finallu)可以被C++编译器支持。


如果你混合使用c和c++异常,注意下面几项:
1.c++异常和c异常不能在一个函数内混合使用。
2.终止处理程序(__finally区块)总会被执行,及时在一个异常被抛出后的展开(执行)期间。
3.在使用/GX编译选项编译的所有模块中,C++异常处理能捕获和保护展开的语义。(??)
4.可能在一些状况下所有对象的析构函数不会被调用。比如,当通过一个未初始化的函数指针去调用一个函数,并且把一个调用前构造的对象当作参数,这时会发生一个C异常,这些对象的析构函数不会在在退栈的时候被调用。

.Exception handling overhead

原创粉丝点击