您的位置:首页 > 其它

条款十二:了解“抛出一个异常”与“传递一个参数”之间的差异

2016-08-18 17:03 447 查看

条款十二:了解“抛出一个异常”与“传递一个参数”之间的差异

void fun(widget w);
void fun(widget& w);
void fun(const widget& w);
void fun(widget* w);
void fun(const widget* w);

void catch(widget w);
void catch(widget& w);
void catch(const widget& w);
void catch(widget* w);
void catch(const widget* w);


  上述代码中前五种是函数调用,函数调用参数传递分为三种形式:传值,传引用,传地址,除了传值会发生对象或者数据的拷贝其他两种都不会触发拷贝动作;而异常处理不同,无论是通过传值还是传引用(传地址不允许,会造成类型不吻合)都会发生对象或者数据的拷贝动作,因为抛出异常意味着离开调用函数返回调用端,这样局部变量会被销毁,如果允许传引用,那么catch将收到的是被销毁的对象。(即使对象不会被销毁,拷贝动作也会发生)

catch(widget& w)
{
throw;
}


catch(widget& w)
{
throw w;
}


  上面的两段代码执行效果不同,第一段代码throw会将异常重新抛出;而第二个代码会抛出一个widget的复本,传值的话会复制两次,会发生拷贝构造,产生的复本只是一个临时对象。

1. execption普通类型的匹配

  在抛出异常时和调用函数有很大的不同是,调用函数如果函数参数类型不匹配,编译器会尝试进行隐式类型转换来匹配参数,而异常类型匹配时不会调用任何隐式类型转换的功能。

void fun(int value)
{
try
{
throw value;
}
catch(double d) //can get the int
{}
}


  在上述代码中catch不可能捕获到value触发的异常,他只能捕捉double类型

2. 继承异常类型捕捉

下面是execption的继承图



  继承类异常的捕获意味着父类异常可以兼容子类异常。

catch(runtime_error)


  上面的代码可以捕获runtime_error的异常也可以捕获继承自runtime_error的异常。因此当写出两个以上的catch,并且catch的对象具有继承关系时,要考虑catch的顺序,将子类catch放在父类catch上面是好的选择,否则子类catch永远不会被执行。

try
{}
catch(range_error)
{}
catch(runtime_error){}


3. 任意类型指针捕获

catch(const void*)


  可以捕获任意类型的指针。

总结

异常对象总会被复制,通过值传递时会复制两次

捕获异常不会做过多的类型转换

继承类的捕获注意匹配次序,父类可以兼容子类
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  异常
相关文章推荐