C++异常机制的实现方式和开销分析:
http://baiy.cn/doc/cpp/inside_exception.htm
C++ 异常 与 ”为什么析构函数不能抛出异常“ 问题:
http://www.cnblogs.com/zhyg6516/archive/2011/03/08/1977007.html
1.当无异常抛出时,其开销就是在函数调用的时候将函数注册到异常处理链中,这些开销很小。
2.但是当异常抛出时,其开销就大了,回溯异常链,用RTTI比配类型,调用析构;但是比传统的那种返回值,层层返回,效率也不会太差。
带来好的好处是代码好维护,减少重复的出错处理代码,并且与逻辑代码分开。
C++标准异常实现的一些主要结构:
编译时确定的:
一. 每个函数一个的EHDL结构,它包括:
1.“try”块表:tblTryBlocks :记录函数中每个try包含的catch入口,参数类型等。
2.“栈回退表”:tblUnwind:存放栈回退所需的析构函数地址与对象在栈中的偏移(偏移是编译可确定的,而对象的实际地址则随函数调用情况的不同而有变化)。
二.每个函数中附加的多个nStep值,标记到目前代码为止需要撤销析构的对象。
运行时确定的:
一.每个函数调用其他函数时将当前的nStep值放入栈中的nStep。此外throw时也会作此操作。以索引“栈回退表”来撤销对象。
二.将当前函数的EHDL地址压入栈中(地址编译时确定,只是运行时压入栈中)
三.将当前的piPrev指向调用链中前一函数的EXP结构。并将当前的EXP结构地址注册到TLS(thread local storage)或同样功能的实现。
上面三个部分组成的EXP结构如下:
struct EXP
{
EXP *ipPrev;
EHDL *piHandle;
int nStep;
}
struct EHDL
{
UNWINDTBL tblUnwind[];
TRYBLOCK tblTryBlocks[];
}
struct UNWINDTBL
{
int nNextldx;
void (*pfnDestroyer)(void* this);
void* pObj;
}
struct TRYBLOCK
{
int nBeginStep; //同过当前nStep来定位属于哪个try
int nEndStep;
CATCHBLOCK tblCatchBlocks[];
}
struct CATCHBLOCK
{
type_info *piType;//RTTI,typeid确定类型是否相同
void *pCatchBlockEntry;
}
1.析构函数中不能抛出异常,会出现内存泄露等情况的资源泄露,但析构函数自己把异常处理了的话,程序是可运行的。否则程序将异常退出。因为此时失去了异常回溯的节点,前面的异常还待处理又如何来处理新的异常。