大胖的部落格

Just a note

  C++博客 :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理 ::
  112 随笔 :: 0 文章 :: 3 评论 :: 0 Trackbacks

异常类:
class TestExcep {
public:
    
//default constructor
    TestExcep(int i=2
        :m_iValue(i)
    
{
        cout
<<"Construct: "<<m_iValue<<endl;
    }


    
//copy constructor
    TestExcep(const TestExcep    &t)
    
{
        m_iValue 
= t.getValue();
        cout
<<"Copy Construct: "<<m_iValue<<endl;
    }


    
//Destructor
    ~TestExcep()
    
{
        cout
<<"Destruct: "<<m_iValue<<endl;
    }


    
int getValue()    const
    
{
        
return m_iValue;
    }


    
void setValue(int i)
    
{
        m_iValue 
= i;
    }
    

private:
    
int    m_iValue;        //to mark the object
}
;


用法
try    //try包含的代码段中可能会抛出异常
{
    
if(1)
    
{
        
throw TestExcep(3);  //抛出异常
    }

}

catch(TestExcep t)   //catch紧跟try,捕获try中抛出的异常
{
    cout
<<"catch "<<t.getValue()<<endl;
}

catch()
{
    cout
<<"catch all exception"<<endl;

}


异常对象总是在抛出点被创建,即使throw 表达式不是一个构造函数调用或者它没有表现出要创建一个异常对象:
TestExcep    t;
throw    t;         //call the copy constructor


一旦异常被处理程序的执行就不能够在异常被抛出的地方继续:
try
{
    
if(1)
    
{
        
throw TestExcep(3);
    }

    cout
<<"untouchable"<<endl;  //一旦异常抛出,这里将不被执行
}


异常对象
catch(TestExcep)  //不创建异常对象
{
    cout
<<"catch exception"<<endl;
}

catch(TestExcep    t)  //调用拷贝构造函数
{
    cout
<<"catch "<<t.getValue()<<endl;  //获取异常对象中的信息
}

catch(TestExcep &t)  //引用类型,不创建新对象
{
        t.setValue(
5);
    cout
<<"catch "<<t.getValue()<<endl;  //可以修改catch到的异常对象
}
为了防止不必要地拷贝大型类对象,class 类型的参数应该被声明为引用。


栈展开
如果throw 表达式位于try 块中,则检查与try 块相关联的catch 子句,看是否有一个子句能够处理该异常。
如果找到一个catch子句则该异常被处理,如果没有找到catch 子句则在主调函数中继续查找。

如果一个程序没有为已被抛出的异常提供catch 子句,程序就调用C++标准库中定义的函数terminate()。


运行时刻机制
对于一个普通函数调用,通过函数重载解析过程,编译器知道在调用点上哪个函数会被真正调用,
但是对于异常处理,编译器不知道特定的throw 表达式的catch 子句在哪个函数中,以及在处理异常之后执行权被转交到哪儿。


重新抛出
catch(TestExcep &t)  //引用
{
    t.setValue(
4);   //改变异常对象信息
    throw;           //重新抛出
}


catch-all
//申请动态内存
int *pi = new int[4];

try     //对申请内存的操作
{
    
//抛出异常
    throw TestExcep();    
}

catch ( ... )   //捕获所有异常,释放内存,再rethrow异常
{
    delete[] pi;  
//释放内存
    throw;    //rethrow异常
}

delete[] pi;  
//释放内存

catch 子句被检查的顺序与它们在try 块之后出现的顺序相同,一旦找到了一个匹配,则后续的catch 子句将不再检查。
这意味着如果catch(...)与其他catch 子句联合使用,它必须总是被放在异常处理代码表的最后,否则就会产生一个编译时刻错误。


异常规范
异常规范跟随在函数参数表之后,它用关键字throw 来指定,后面是用括号括起来的异常类型表。

如果一个函数声明没有指定异常规范,则该函数可以抛出任何类型的异常。
空的异常规范保证函数不会抛出任何异常,例如:
void func() throw();

如果函数抛出了一个没有被列在异常规范中的异常,在编译时刻编译器不可能知道,只能在运行时刻才能被检测出来,
调用C++标准库中定义的函数unexpected(),unexpected()的缺省行为是调用terminate()。

如果该函数自己处理该异常,并且该异常在逃离该函数之前被处理掉,那么一切都不会有问题:
void Test( ) throw(TestExcep)
{
    
try 
    
{
        
throw AnotherExcep();
    }

    
// 处理抛出的异常
    catch ( AnotherExcep) {
    
// 做一些必要的工作
    }

}
   // ok, unexpected()没有被调用

谨慎使用异常规范,因为很难保证调用的其它函数不抛出本函数异常规范之外的异常:
void ThrowDouble() throw(double)
{
    
throw 5.5;
}
   

void ThrowNone() throw()
{
    
//在声明为不抛出异常的函数里调用了抛出异常的函数
    ThrowDouble();
}



类型转换:
与函数调用不同,当throw的异常类型和catch的类型不一致时,不会进行类型转换,但有两个例外:
1、父类型异常可以catch到子类对象。
2、void*类型可以catch到所有指针类型。
    try
    
{
        
throw 1.5;
    }

    
catch(int)
    
{
        
//无法catch double类型的对象
        cout<<"catch int"<<endl;
    }

    
catch(double)
    
{
        cout
<<"catch double"<<endl;
    }

posted on 2009-05-10 14:31 大胖 阅读(232) 评论(0)  编辑 收藏 引用 所属分类: C++

只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理