首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 开发语言 > 编程 >

关于抛出错误和清栈

2012-12-21 
关于抛出异常和清栈构造函数中异常:?1.在无继承关系的前提下,构造函数中抛出异常未尝不可。 因为在对象没能

关于抛出异常和清栈

构造函数中异常:

?

1.在无继承关系的前提下,构造函数中抛出异常未尝不可。 因为在对象没能构造完整的情况下,是不会去调用析构函数的。

2.在有继承关系的情况下,构造函数中抛出异常可能会引起问题

?

2.1如果基类中有纯虚函数,而且在基类的析构函数中有被调用的话,会得到一个 pure virtual function call的异常

2.2如果基类中有纯虚函数,但是基类的析构函数中没有被调用到,是没有关系的。

?

对2.1的猜想:

因为派生类构造函数在执行的时候,会先去调用基类的构造函数。所以如果异常产生于派生类,系统会认为基类已经构造完毕,但是这时因为派生类还没有构造完毕。又因为此时产生异常,系统需要进行Stack Unwind的操作。会释放认为已经构造完毕的对象。于是,被认为是已经构造完毕的基类对象的析构函数会被系统调用。

猜想一:因为派生对象还没完成构造,导致晚绑定(个人理解为虚函数表未被写入)还未完成。所以只能使用当前可用的调用,即纯虚函数。

? ? ? ? 猜想二:因为还没构造完派生对象,所以目前的this指针指向的类型,即当前对象类型,仍然被认为是基类的类型,于是。只会调用基类对应的函数。

?

?

#ifndef IDISPOSABLE_H#define IDISPOSABLE_Hnamespace 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

?

编译器exception-unhandle 时是否会 stack unwindg++ 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否

?

热点排行