More Effective C++ 条款12 了解”抛出一个exception"与“传递一个参数”或“调用一个虚函数”之间的差异

1. 函数return值与try块throw exception、函数接收参数与catch字句捕获异常相当类似(不仅声明形式相像,函数参数与exception传递方式都有三种:by value,by reference , )。

2. 尽管函数调用与异常抛出相当类似,“从抛出端传递一个exception到catch子句”和“从函数调用端传递一个实参到被调函数参数”仍然大有不同:

1)调用一个函数,控制权会最终回到调用端(除非函数失败以致无法返回),但是抛出一个exception,控制权不会再回到抛出端

可以简单理解函数调用作用域是“外—里—外”的转换,而异常抛出是“里—外—···”的转换(只是便于理解,实际上这个比方并不正确)

2)如果函数调用的参数是按引用传递的,那么实参不会被复制,但无论catch接收的异常是按引用还是按值传递,被抛出的异常对象至少被复制一次,原因在于栈展开过程中局部对象都被销毁,因而需要产生一个临时对象保存被throw的异常,这与函数return时用一个临时对象来暂时保存return的对象是一样的(函数return存在NRV(有的也叫RVO)优化,可以省略调用拷贝构造函数)。也就是说,在第一个catch子句接受异常时,那个异常已经是被复制过一次的临时对象,如果catch子句的参数是按值传递,那么临时对象还需要再被复制一次。因此异常处理通常要付出较高的代价。

3)函数可以返回引用,catch子句不可能重新抛出一个引用,对于以下代码:

1 try{
2     throw Derived;
3 }
4 catch(Base & tmp){
5     throw tmp;
6 }

catch子句重新throw的过程中创建临时对象并调用拷贝构造函数,由于构造函数不可能为虚(虽然可以采取其他方式形成虚的"伪构造函数"),这意味着如果经由catch子句抛出的异常已经变为了Base类型(尽管传入的时候是按引用传递的),此时异常是当前exception的副本。如果要重新抛出Derived类型对象可以采用以下代码:

1 try{
2     throw Derived
3 }
4 catch(Based& tmp){
5     throw;
6 }

这样抛出的是当前的exception

4)函数调用与异常抛出参数匹配规则不同,如果有多个重载函数,那么选择参数最为匹配的那个,找不到匹配的函数则进行实参的转换尽量匹配上,有多个相当匹配的函数则发生二义性,也就是说,函数匹配采用“最佳吻合”策略;

异常抛出则不同,catch子句依出现顺序做匹配尝试,一旦找到一个“相对兼容的”类型就视为匹配成功,就算后面有完全匹配的类型也会被无视,也就是说,异常抛出的参数匹配采用“最先吻合”策略,也正是由于这种策略,异常抛出的参数所允许的转换比函数实参匹配所允许的转换要严格得多,只允许以下转换:

1)“继承架构中的类转换”:派生类异常可以被基类参数捕获,因此catch子句出现顺序应该是先派生类再基类

2)非const到const的转换

3)数组转为数组类型的指针

4)其他指针转“无型指针”(void*指针)

时间: 2024-08-08 21:53:12

More Effective C++ 条款12 了解”抛出一个exception"与“传递一个参数”或“调用一个虚函数”之间的差异的相关文章

More Effective C++----(12)理解"抛出一个异常"与"传递一个参数"或"调用一个虚函数"间的差异

Item M12:理解"抛出一个异常"与"传递一个参数"或"调用一个虚函数"间的差异 从语法上看,在函数里声明参数与在catch子句中声明参数几乎没有什么差别: class Widget { ... }; //一个类,具体是什么类 // 在这里并不重要 void f1(Widget w); // 一些函数,其参数分别为 void f2(Widget& w); // Widget, Widget&,或 void f3(const W

try ,finally都抛出异常如何处理.如果try中抛出了异常,在控制权转移到调用栈上一层代码之前, finally 语句块也会执行,如果finally抛出异常,try语句快抛出的那个异常就

package com.github.jdk7; import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * try ,finally都抛出异常如何处理.如果try中抛出了异常,在控制权转移到调用栈上一层代码之前, * finally 语句块也会执行,如果finally抛出异常,try语句快抛出的那个异常就丢失了. * * @author doctor * * @since 2014年

More Effective C++ 条款13 以reference方式捕捉exception

1. 由条款12知,如果catch子句捕获异常采用按值传递,那么被抛出的异常要被复制两次,这降低了效率,而且将派生类对象传给基类对象有可能会产生切割问题,但是按值传递也有它的好处,在catch子句重新throw异常的时候,它可以选择throw经catch子句处理过的异常还是原来的异常,这增加了灵活性(throw;) 2. 按指针传递似乎可以避免异常的复制,(虽然指针还是要被复制,不过4字节的代价不高),但是要注意指针指向的不能是局部对象,因为局部对象会被销毁,这就要求指针指向动态分配的内存,但由

Effective C++ 条款25 考虑写出一个不抛出异常的swap函数

1. swap是STL的一部分,后来成为异常安全性编程(exception-safe programming)(见条款29)的一个重要脊柱,标准库的swap函数模板定义类似以下: namespace std{ template<typename T> swap(T& lhs,T& rhs){ T temp(lhs); lhs=rhs; rhs=temp; } } 只要T类型支持拷贝构造以及拷贝赋值,标准库swap函数就会调用T的拷贝构造函数和拷贝构造操作符完成值的转换,但对于某

Effective C++ 条款12

复制对象时,勿忘其每一个成分 作者在本节条款提醒我们,在多重继承的情况下进行copy或者copy assignment 的operator=的编写时,一定要考虑base 类部分数据的初始化后者复制. 对比一下代码: class Cutsomer { -- private: string name; string telphone; }; class PriorityCustomer:public Cutsomer { public: PriorityCustomer() { cout<<&qu

Effective C++ -----条款12: 复制对象时勿忘其每一个成分

Copying函数应该确保复制“对象内的所有成员变量”及“所有base class成分”. 不要尝试以某个copying函数实现另一个copying函数.应该将共同机能放进第三个函数中,并由两个coping函数共同调用.如果你发现你的copy构造函数和copy assignment操作符有相近的代码,消除重复代码的做法是,建立一个新的成员函数给两者调用.这样的函数往往是private而且常被命名为init.这个策略可以安全消除copy构造函数和copy assignment操作符之间的代码重复.

effective c++ 条款12:复制对象时勿忘其每一个成分

记住:拷贝函数应该确保复制"对象内的所有成员变量"及"所有父类成分".不要尝试以某个拷贝函数实现另一个拷贝函数.应该将共同机能放进第三个函数中,并由两个拷贝函数共同调用. 下面是一个类实现了自己的拷贝函数,一起正常. void logCall(const string& funcName): class Customer { public: ... Customer(const Customer& rhs); Customer& operat

VS2013 抛出 stackoverflow exception 的追踪

本公司使用VWG.Caslte ActiveRecord.CSLA.net .Quantz.net 等组件做为公司的开发基础,自2007年以来,一直工作正常,但最近(2015.12月)以来,打开MDAA项目时,VS 总是自动 崩溃(Crashed)后,自动启动,追踪调试后,只得到了 "StackOverflow", 堆栈溢出. 知道了这个问题,但总是找不到原因应该如何处理:尝试的方法有: 1.更新VS update5 ,故障依旧: 2.更新 VWG 至 10.0.4,故障依旧: 3.上

Sub的构造函数抛出了Exception异常增加新的catch块才能解决

在使用mingw64之前,由于其支持较多的编译类型,所以其安装包较多,通常采用的是“穷举+回溯”的思想,即从入口开始,顺着某一个方向出发,若能够走通,就继续往前走:若不能走通,则退回原路,换一个方向继续向前探索,直到所有的通路都探寻为止.因此本文依据这种“穷举+回溯”的思想,设计一个求解迷宫的程序. 鱼目混珠者有高明之处,左右逢源之能,这本无可厚非,但如果一种投机的技术态度,堂而皇之的成为青年的学习榜样,作为对技术有态度.有坚持的我,在此时此刻,有义务,甚至要义无反顾的站出来反对并碾碎这样的丑恶