原文出处:http://blog.youkuaiyun.com/wuzh1230/article/details/7212817
函数与子函数之间的调用关系可以用一个链来表示,调用连,相关的一个重要数据结构就是栈帧,子函数返回的时候,栈展开,构造在栈上的对象被编译器设置的析构函数析构销毁。
类似的,windows上的结构化异常处理也有一个类似的异常处理链,而且这个链刚好也是在栈上构造的,但是和函数正常的链是各自独立的。当某一个子函数发生异常的时候,就不能走正常的调用连返回,进而析构对象;这个时候,需要走异常链来回溯,展开异常调用链,所有附着在异常链上的对象,在异常链的第二次调用(unwind处理,第一次是搜索异常处理者)的时候析构。
函数调用 A ----------------------> B ---------------------> C ------------------------->D
正常调用链 CallNode_A--------> CallNode_B ---------->CallNode_C------------>CallNode_D
异常链 ExcpNode_A-------> ExcpNode_B------------------------------------------->!!BOMB!!<
每一个节点都包含了该函数对应的对象的析构操作,正常调用链也好,异常链也好,都是这样的,这些是由C++编译器完成的。每一个call操作,c++编译器产生一个子函数栈帧节点。每一个try-catch语句,c++语句构造一个异常链节点。
但是,如果一个程序员在C函数里面没有写try-catch,但是D函数里面有try-catch语句,而且运行的时候,在D函数里面发生了异常,那么C函数里面的生成的所有对象得不到析构的机会。
程序代码
- // debugee.cpp : Defines the entry point for the console application.
- //
- #include "stdafx.h"
- class Object
- {
- public:
- Object(const char tag) : m_tag(tag)
- {printf("Object [%c] %p\n", m_tag, this);};
- ~Object()
- {printf("~Object [%c] %p\n", m_tag, this);};
- private:
- char m_tag;
- };
- void D(void)
- {
- Object d('D');
- *(int *)0 = 0;
- }
- void C(void)
- {
- Object c('C');
- D();
- }
- void B(void)
- {
- Object b('B');
- try
- {
- C();
- }catch(...)
- {
- printf("B caught exception.\n");
- }
- }
- void A(void)
- {
- Object a('A');
- try
- {
- B();
- }catch(...)
- {
- printf("A caught exception.\n");
- }
- }
- int main(int argc, char* argv[])
- {
- A();
- return 0;
- }
// debugee.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
class Object
{
public:
Object(const char tag) : m_tag(tag)
{printf("Object [%c] %p\n", m_tag, this);};
~Object()
{printf("~Object [%c] %p\n", m_tag, this);};
private:
char m_tag;
};
void D(void)
{
Object d('D');
*(int *)0 = 0;
}
void C(void)
{
Object c('C');
D();
}
void B(void)
{
Object b('B');
try
{
C();
}catch(...)
{
printf("B caught exception.\n");
}
}
void A(void)
{
Object a('A');
try
{
B();
}catch(...)
{
printf("A caught exception.\n");
}
}
int main(int argc, char* argv[])
{
A();
return 0;
}
输出:
注意:
vc编译器的版本差异和编译选项的差异,vc2005的/EHsc标记。
- class Object
- {
- public:
- Object(const char tag) : m_tag(tag)
- {printf("Object [%c] %p\n", m_tag, this);};
- ~Object()
- {printf("~Object [%c] %p\n", m_tag, this);};
- private:
- char m_tag;
- };
- void E(void)
- {
- Object e('E');
- //try
- {
- throw("");
- }
- //catch (...)
- {
- }
- }
- void D(void)
- {
- Object d('D');
- E();
- }
- void C(void)
- {
- Object c('C');
- D();
- }
- void B(void)
- {
- Object b('B');
- //try
- {
- C();
- }
- //catch(...)
- {
- printf("B caught exception.\n");
- }
- }
- void A(void)
- {
- Object a('A');
- try
- {
- B();
- }catch(...)
- {
- printf("A caught exception.\n");
- }
- }
- int main(int argc, char* argv[])
- {
- A();
- return 0;
- }
class Object
{
public:
Object(const char tag) : m_tag(tag)
{printf("Object [%c] %p\n", m_tag, this);};
~Object()
{printf("~Object [%c] %p\n", m_tag, this);};
private:
char m_tag;
};
void E(void)
{
Object e('E');
//try
{
throw("");
}
//catch (...)
{
}
}
void D(void)
{
Object d('D');
E();
}
void C(void)
{
Object c('C');
D();
}
void B(void)
{
Object b('B');
//try
{
C();
}
//catch(...)
{
printf("B caught exception.\n");
}
}
void A(void)
{
Object a('A');
try
{
B();
}catch(...)
{
printf("A caught exception.\n");
}
}
int main(int argc, char* argv[])
{
A();
return 0;
}
不带/EHsc产生的结果符合预期
转载于:https://blog.51cto.com/freetoskey/976760