C++ primer 摘要《异常处理》20090122

来源:互联网 发布:最新网络推广任务 编辑:程序博客网 时间:2024/06/03 21:19

 ===11.1 抛出异常===
异常是个对象,throw 表达式后要跟一个对象
    throw popOnEmpty(); //popOnEmpty是个类,这里使用了构造函数构造对象
虽然异常往往是class 类型的对象,但是throw 表达式也可以抛出任何类型的对象
    enum EHstate { noErr, zeroOp, negativeOp, severeError };
    int mathFunc( int i ) {
    if ( i == 0 )
       throw zeroOp; // 枚举类型的异常
    ...

===11.2 try 块===
//我们可以声明整个包含在try 块中的函数,在这种情况下,我们不是把try 块放在函数定义的内部
//而是把函数体整个包含在一个函数try 块
int func()
    try { //try 在函数体的开始花括号之前
        iStack stack( 32 );
        stack.display();
        for ( int ix = 1; ix < 51; ++ix )
        {
            // ...       
        }
        return 0;
    }
    catch (pushOnFull) {
    // 这里不能引用 stack
    }
    catch ( popOnEmpty ) {
    // 这里不能引用 stack
    }

如果这些catch 子句不包含返回语句,在catch 子句完成它的工作之后,程序的执行将在catch 子句列表的最后子句之后继续进行

===11.3.1异常对象===
enum EHstate { noErr, zeroOp, negativeOp, severeError };
enum EHstate state = noErr;

int mathFunc( int i ) {
   if ( i == 0 ) {
      state = zeroOp;
      throw state; // 创建异常对象,throw 表达式创建了一个类型为EHstate的异常对象,并且用全局对象state 的值初始化该对象
   }
   // 否则, 正常处理流程继续
}
void calculate( int op ) {
    try {
        mathFunc( op );
    }
    catch ( EHstate &eObj ) {
        // 修正异常情况
        eObj = noErr; // 全局变量 state 没有被修改, 因为这里的eObj引用的并不是全局对象,而是由throw创建的异常对象
    }
}
===11.3.2 栈展开===
异常匹配查找
如果一个程序没有为已被抛出的异常提供catch 子句,程序就调用C++标准库中定义的函数terminate()
===11.3.3 重新抛出===
catch ( exception eObj ) {
    if ( canHandle( eObj ) )
        // 处理异常
        return;
    else
        // 重新抛出它, 并由另一个catch 子句来处理
        throw; //被重新抛出的异常就是原来的异常对象
}

//因为eObj 不是引用,所以catch 子句接收到的是异常对象的局部拷贝
catch ( EHstate eObj ) {
    // 做某些修正
    // 试图修改异常对象,这里只是修改了局部拷贝
    eObj = severeErr;
    // 这里并没有改变抛出的异常对象值
    throw;
}
//下面实现了异常对象的修改
cacth ( EHstate &eObj ) {
    // 修改异常对象
    eObj = severeErr;
    // 被重新抛出的异常的值是 severeErr
    throw;
}

try {
    stack.display();
    for (int ix = 1; ix < 51; ++ix )
    {
        // 与前面相同
    }
}
catch ( pushOnFull ) {}
catch ( popOnEmpty ) { }
catch (...) { } // 必须是最后一个catch 子句       

===11.4 异常规范===
注意项:
1、异常规范跟随在函数参数表之后
class iStack {
public:
    // ...
    void pop( int &value ) throw(popOnEmpty);
    void push( int value ) throw(pushOnFull);
private:
    // ...
};
异常规范是函数和程序余下部分之间的协议,它保证该函数不会抛出任何没有出现在其异常规范中的异常。
但是,如果pop抛出popOnEmpty以外的异常,编译器并不会报错,只有在运行时刻才能被检测到

2、如果函数声明指定了一个异常规范,则同一函数的重复声明必须指定同一类型的异常规范。
// 同一函数的两个声明
extern int foo( int = 0 ) throw(string);
// 错误: 异常规范被省略
extern int foo( int parm ) { }

3、空的异常规范保证函数不会抛出任何异常
extern void no_problem() throw();
4、在被抛出的异常类型与异常规范中指定的类型之间不允许类型转换
int convert( int parm ) throw(string)
{
    // ...
    if ( somethingRather )
    // 程序错误:
    // convert() 不允许 const char* 型的异常
    throw "help!"; //需要显示转换throw string( "help!" );
}

===11.4.1 异常规范与函数指针===
用作初始值或右值的指针异常规范必须与被初始化或赋值的指针异常规范一样或更严格
void recoup( int, int ) throw(exceptionType);
void no_problem() throw();
void doit( int, int ) throw(string, exceptionType);
// ok: recoup() 与 pf1 的异常规范一样严格
void (*pf1)( int, int ) throw(exceptionType) = &recoup;
// ok: no_problem() 比 pf2 更严格
void (*pf2)() throw(string) = &no_problem;
// 错误: doit()没有 pf3 严格
void (*pf3)( int, int ) throw(string) = &doit;

 

原创粉丝点击