- 浏览: 76780 次
- 性别:
- 来自: 上海
文章分类
构造函数中异常:
1.在无继承关系的前提下,构造函数中抛出异常未尝不可。 因为在对象没能构造完整的情况下,是不会去调用析构函数的。
2.在有继承关系的情况下,构造函数中抛出异常可能会引起问题
2.1如果基类中有纯虚函数,而且在基类的析构函数中有被调用的话,会得到一个 pure virtual function call的异常
2.2如果基类中有纯虚函数,但是基类的析构函数中没有被调用到,是没有关系的。
对2.1的猜想:
因为派生类构造函数在执行的时候,会先去调用基类的构造函数。所以如果异常产生于派生类,系统会认为基类已经构造完毕,但是这时因为派生类还没有构造完毕。又因为此时产生异常,系统需要进行Stack Unwind的操作。会释放认为已经构造完毕的对象。于是,被认为是已经构造完毕的基类对象的析构函数会被系统调用。
猜想一:因为派生对象还没完成构造,导致晚绑定(个人理解为虚函数表未被写入)还未完成。所以只能使用当前可用的调用,即纯虚函数。
猜想二:因为还没构造完派生对象,所以目前的this指针指向的类型,即当前对象类型,仍然被认为是基类的类型,于是。只会调用基类对应的函数。
#ifndef IDISPOSABLE_H #define IDISPOSABLE_H namespace odbclib { class IDisposable { protected: virtual void dispose() = 0; friend class MasterObject; }; } #endif
#ifndef MASTERRESOURCE_H #define MASTERRESOURCE_H #include "odbclib.h" namespace odbclib { class MasterResource :public virtual RelatedResource { public: MasterResource(); virtual ~MasterResource(); protected: typedef stack<SlaveResource*> SlaveStack; void addSlave(SlaveResource &slave); void removeSlave(SlaveResource &slave); virtual void onDisposing(); void disposeSlaves(); private: SlaveStack m_slaves; friend class SlaveResource; }; } #endif
#include "odbclib.h" namespace odbclib { MasterResource::MasterResource(){} MasterResource::~MasterResource() { this->dispose(); } void MasterResource::addSlave(SlaveResource &slave) { m_slaves.push(&slave); } void MasterResource::removeSlave(SlaveResource &slave) { SlaveStack slaves; while(!m_slaves.empty()) { SlaveStack::reference iter = m_slaves.top(); m_slaves.pop(); if(&slave == iter) continue; slaves.push(iter); } while(!slaves.empty()) { m_slaves.push(slaves.top()); slaves.pop(); } } void MasterResource::disposeSlaves() { SlaveStack slaves(m_slaves); while(!slaves.empty()) { SlaveStack::reference slave = slaves.top(); slave->dispose(); slaves.pop(); } } void MasterResource::onDisposing() { this->disposeSlaves(); } }
说明:当MasterObject的disposeSelf是纯虚函数。但是MasterObject的派生类在构造函数中抛出异常,就会导致在Stack unwind期间得到一个pure virtual function call
注意:如果不在派生类的析构函数处显式调用基类的虚函数,而放任由系统调用。则会由于派生类的析构函数已经从虚函数表内移除该虚函数,导致调用的是基类的虚函数。如果此虚函数同样是 纯虚函数,则同样也会得到一个pure virtual function call的异常
=======================================================================
2011-9-23 补充:
=======================================================================
很多资料和帖子上都说 如果 构造函数中抛出异常 ,虽然对象本身是不会被析构,但是对象的成员对象会被析构。
其实这个说法是有非常严重的缺陷的。
class Resource { public: Resource() { cout<<"[Resource]constructing..."<<endl; throw runtime_error("asdfasdfasdf"); } ~Resource() { cout<<"[Resource]destructing..."<<endl; } }; class Ctor { public: Ctor() { cout<<"[Ctor]constructing..."<<endl; } virtual ~Ctor() { cout<<"[Ctor]destructing..."<<endl; } private: Resource m_resource; };
如果main中是这样写的:
int main(int argc,char* argv[])
{
try{
Ctor c;
}
catch(...)
{}
return 0;
}
那么,很幸运的,你可以见识到传说中的stack unwind
但是如果仅仅是下面这样
int main(int argc,char* argv[])
{
Ctor c;
return 0;
}
那就惨了。虽然不知道这样会不会有stack unwind发生。但是很明显的是 c的析构函数是不会被调用到的。
这个问题说大不大,说小不小。
轻者最多是程序退出。然后会完全释放程序所占用的内存,和一些与程序逻辑不相关的资源。
重者数据库连接未断开,事务还没有commit,这时另一个也来了,那就死锁了。很杯具吧!
程序退出的时候很多业务逻辑中重要的资源是不会被程序释放的,虽然这也是情理之中。
但是如此一来。岂不是每次出异常都要加try-catch块,以保证对象的析构函数被调用?
或者每次写main都要来上一个try-catch
As far as I know, C++ standard guarantess that destructors for local variables will be called during the stack unwinding only if the exception is handled (caught and not rethrown). If it is not handled, then the destructors may or may not be called. How do most compilers implement this?
15.5.1p2: "In the situation where no matching handler is found, it is implementation-defined whether or not the stack is unwound before terminate()is called. In all other situations, the stack shall not be unwound before terminate()is called. An implementation is not permitted to finish stack unwinding prematurely based on a determination that the unwind process will eventually cause a call
to terminate()."
I could not verify the quote, hence I am asking for comments.
Roman Werpachowski [Recognized User] Send private email
Thursday, September 27, 2007
Roman Werpachowski [Recognized User] Send private email
Thursday, September 27, 2007
g++ 4.1.2 does not unwind when there is an unhandled exception, according to the test program posted.
Stephen Depooter
Thursday, September 27, 2007
这说明如果没有对异常有catch,那么编译器生成的代码是否会执行stack unwind完全是由编译器自己决定的。
并且已经有好心人测试过几个版本的g++
编译器 | exception-unhandle 时是否会 stack unwind |
g++ version 2.96 20000731 (Red Hat Linux 7.3 2.96-110) | 是 |
g++ version 3.3.6 (PLD Linux) | 否 |
g++ 4.1.2 | 否 |
g++ 4.5.2 | 否 |
vc++ 2010 | 否 |
发表评论
-
pthread_rwlock_t 未定义的问题
2016-08-06 15:02 1369最近在linux上次编译时出现pthread_rwlock ... -
二级指针 const 参数
2013-01-11 22:33 1982http://www.parashift.com/c++-fa ... -
tricks
2012-12-31 14:21 716#include <typeinfo> #inc ... -
多输出带前缀输出流
2012-10-29 11:37 946http://stackoverflow.com/questi ... -
inherit the ostream
2012-10-26 16:02 802class cdebug_stream :public ost ... -
模板参数 函数指针
2011-12-22 13:12 2330http://stackoverflow.com/questi ... -
event
2011-08-19 14:42 738#ifndef ODBCLIB_CORE_EVENT_EVEN ... -
c++ Delegate
2011-08-06 19:59 1533#ifndef DUMMYCLASS_H #defin ... -
Nullable (bug)
2011-06-26 23:45 899#ifndef NULLABLE_H #define ... -
C++ 接异常时的注意
2011-06-24 23:55 808void test1() { try { ... -
类成员函数模板特化 默认参数
2011-06-19 11:23 2424#ifndef MEMORYBLOCK_H #defi ... -
类成员函数模板特化
2011-06-12 20:20 2810//header file namespace odb ...
相关推荐
汇兑风险、清关和清税.pptx
中石化加油卡开户和清户顺序.docx
现金收付流程和清分整点规范方案.doc
界收费站后高速公路通行秩序高效、稳定,根据 ETC 费显和清分结算系统 优化工程要求,结合《取消高速公路省界收费站车道系统实施指南》,对 ETC/MTC 混合车道系统进行优化设计,形成《ETC 费显和清分结算系统优化 ...
税控盘,金税盘,税务UKey抄税和清卡接口
基于声学分析和机器学习构建咳嗽和清嗓分类模型.pdf
证券支付(银行转证券、证券转银行)和清结算的流程.docx
《宿新市徐公店》《四时田园杂兴(其二十五)》《清平乐_村居》教学反思2.pdf
为满足交通运输部在取消高速公路省界收费站不停车电子收费系统费显和清分结算系统优化试点工程中对ETC通行车辆分段计费和计费结果的要求,重点阐述门架元整计费,固定折扣率出口元整计费和差异化折扣率出口元整计费等3...
经过检测发现采煤机头、移架处和清煤处定点呼尘超标;采煤司机、清煤工个体呼尘超标,原因是采煤机外喷雾水压不够,喷雾不能覆盖整个采煤机头部。后经过增加喷雾压力复测结果全部合格,表明高压喷雾能够有效降尘。
设计一个基于51单片机的4位电子计数器,使用4数码管进行数字显示,显示范围为-999~999,并用3个按钮对显示数字进行独立控制,分别实现数字加1、减1和清0的功能。
石拉乌素煤矿风井由立井转平巷施工过程中,利用立井凿井设施,采用凿岩台车钻眼、防爆装载机装岩、防爆胶轮车运输、井底水窝储矸、中心回转抓岩机抓岩、吊桶提升的作业方式,工作面全断面一次爆破和清底。采用胶带输送...
1.把下载下来的“JTAG.rar”里面的JTAG文件夹解压到C般跟目录。 2.选择“开始”-“运行”,写入“%systemroot%\...一般我们只要清除NVRAM之后路由就可以正常启动了,也可以清NVRAM和清kernel之后重新TFTP刷固件进去就行
循环对XF位置1和清0,用示波器可以在XF脚检测到电平高低周期性变化 常用于检测DSP是否工作。
维吾尔语的塞音同英语有清浊之分,对维吾尔语中的浊塞音和清塞音进行声学研究,从"维吾尔语语音声学参数库"中选取466个包含浊塞音及981个清塞音的词,采集了它们时长,无声段(GAP)和嗓音起始时间(VOT)这3种最...
根据该项工程要求,介绍了CZ-6D型冲击钻机在定位放线、桩机就位、冲击成孔和清孔等冲击成孔施工过程中所采取的措施,并对其质量控制要点进行了重点说明。结果发现,采用冲击成孔灌注桩,大大提高了施工效率,工程质量达到...
封装的一个比较常用的css类,比如清除一些标签的默认样式(ul , a , h1 等),左浮动,右浮动和清浮 ,盒模型的转换,文本修饰等。
我进行了整理和纠错,内容比较全面,15天学习C语言Windows程序设计,一天一章,15天后,对winAPI编程有相对全面和清淅的认识,对新手非常有帮助。
阐述了郑州清梳联在纺纯棉纱时的推荐流程配置、各单元机和清梳联系统的主要工艺优化及使用情况,给出了主要单元机和清梳联系统的上机工艺的优化过程及最终结果,并提出了用好清梳联的建议,对棉纺厂用清梳联纺出好的纯...