昨晚又纠结于我的异常处理模块,由于一直考虑DLL的封装性,采用接口方式导出异常管理器,再调用异常管理器的函数成员来创建异常对象,由于返回的是异常对象的接口指针,结果引出了新问题,创建的对象无法在抛出异常时被自动析构。郁闷中只好改变创建异常对象的方法。经过几次血的教训下得出了下面几点注意事项:
1、在异常作用域内,被new出来的对象(变量)在抛出异常时不会被自动析构(释放),所以在抛出异常前要手动将其析构掉(释放)。
2、catch到的对象(变量)只是被throw的对象的一个拷贝副本,抛出异常之后原对象被自动析构(释放)。
3、当throw对象(变量)的指针,拷贝的只是指针变量本身,而不是其所指的对象。如果在catch前,指针所指的对象(变量)已经在异常作用域内被析构(释放),那么在catch时访问指针所指的对象(变量)将会出错。
4、当throw对象(变量)的引用,拷贝的是引用的对象,而不只是拷贝引用名称。
5、catch对象时,应该先catch子类对象后catch父类对象,否则子类对象会先在catch父类对象时被捕获,而catch子类对象时将捕获不到它。
以上几点注意事项可以通过运行下面的代码得到验证:
#include <iostream>
using namespace std;
/* 基类接口 */
class IBase
{
public:
virtual ~IBase(void)
{}
virtual void speak(void) = 0;
};
/* 基类 */
class CBase:public IBase
{
public:
CBase(void)
{
cout << "CBase Construction !" << endl;
}
virtual ~CBase(void)
{
cout << "CBase Destruction !" << endl;
}
virtual void speak(void)
{
cout << "I am CBase's Object !" << endl;
}
};
/* 派生类 */
class CDerive:public CBase
{
public:
CDerive(void)
{
cout << "CDerive Construction !" << endl;
}
~CDerive(void)
{
cout << "CDerive Destruction !" << endl;
}
void speak(void)
{
cout << "I am CDrive's Object !" << endl;
}
};
/* 异常测试函数,用于抛出各种类型的对象 */
void ExceptionTest(int i)
{
switch (i)
{
case 1:
{
cout << "--IBase * pobjIB = new CBase--" << endl;
IBase * pobjIB = new CBase;
throw(pobjIB);
break;
}
case 2:
{
cout << "--IBase * pobjIB = new CDerive--" << endl;
IBase * pobjIB = new CDerive;
throw(pobjIB);
break;
}
case 3:
{
cout << "--CBase * pobjCB = new CBase--" << endl;
CBase * pobjCB = new CBase;
throw(pobjCB);
break;
}
case 4:
{
cout << "--CBase * pobjCB = new CDerive--" << endl;
CBase * pobjCB = new CDerive;
throw(pobjCB);
break;
}
case 5:
{
cout << "--CDerive * pobjCD = new CDerive--" << endl;
CDerive * pobjCD = new CDerive;
throw(pobjCD);
break;
}
case 6:
{
cout << "--CBase & objrCB = objCB--" << endl;
CBase objCB;
CBase & objrCB = objCB;
throw(objrCB);
break;
}
case 7:
{
cout << "--CBase & objrCB = objCD--" << endl;
CDerive objCD;
CBase & objrCB = objCD;
throw(objrCB);
break;
}
case 8:
{
cout << "--CBase & objrCB = objCD--" << endl;
CDerive objCD;
CDerive & objrCD = objCD;
throw(objrCD);
}
case 9:
{
cout << "--CBase objCB--" << endl;
CBase objCB;
throw(objCB);
break;
}
case 10:
{
cout << "--CDerive objCD;--" << endl;
CDerive objCD;
throw(objCD);
break;
}
}
};
int main(void)
{
try
{
ExceptionTest(7);
}
catch(CDerive * pobjCD)
{
cout << "==catch(CDerive * bobjCD)==" << endl;
pobjCD->speak();
}
catch(CBase * pobjCB)
{
cout << "==catch(CBase * pobjCB)==" << endl;
pobjCB->speak();
}
catch(IBase * pobjIB)
{
cout << "==catch(IBase * pobjIB)==" << endl;
pobjIB->speak();
}
catch(CDerive objCD)
{
cout << "==catch(CDerive objCD)==" << endl;
objCD.speak();
}
catch(CBase objCB)
{
cout << "==catch(CBase objCB)==" << endl;
objCB.speak();
}
catch(...)
{
cout << "catch(...)" << endl;
}
return 0;
};