C++ 用异常使得可以将正常执行代码和出错处理区别开来。 比如一个栈,其为空时,调用其一个pop 函数,接下来怎么办? 栈本身并不知道该如何处理,需要通知给其调用者(caller),因为只有调用者清楚接下来该怎么做。 异常,就提供了一个很好机制。 但是异常需要操作系统,编译器,RTTI的特性支持。
下面围绕一个问题 “为什么析构函数不能抛出异常?” 展开C++中异常的实现。
Effective C++ 里面有一条”别让异常逃离析构函数“,大意说是Don't do that, otherwise the behavior is undefined. 这里讨论一下从异常的实现角度,讨论一下为什么不要 ?
1. 函数调用框架和SEH( Structure Error Handling)
程序
1 int widget( int a, int b)
2 {
3 return a + b;
4 }
5
6 int bar(int a, int b)
7 {
8 int c = widget(a, b);
9 return c;
10 }
11
12 int foo( int a, int b)
13 {
14 int c=bar(a, b);
15 return c;
16 }
17
18 int main()
19 {
20 foo( 1, 2);
21 }
2 {
3 return a + b;
4 }
5
6 int bar(int a, int b)
7 {
8 int c = widget(a, b);
9 return c;
10 }
11
12 int foo( int a, int b)
13 {
14 int c=bar(a, b);
15 return c;
16 }
17
18 int main()
19 {
20 foo( 1, 2);
21 }
其汇编代码
1 PUBLIC ?widget@@YAHHH@Z ; widget
2 ; COMDAT ?widget@@YAHHH@Z
3 _TEXT SEGMENT
4 _a$ = 8; size = 4
5 _b$ = 12; size = 4
6 ?widget@@YAHHH@Z PROC ; widget, COMDAT
7
8 ; 4 : {
9
10 push ebp
11 mov ebp, esp
12 sub esp, 192; 000000c0H
13 push ebx
14 push esi
15 push edi
16 lea edi, DWORD PTR [ebp-192]
17 mov ecx, 48; 00000030H
18 mov eax, -858993460; ccccccccH
19 repstosd
20
21 ; 5 : return a + b;
22
23 mov eax, DWORD PTR _a$[ebp]
24 add eax, DWORD PTR _b$[ebp]
25
26 ; 6 : }
27
28 pop edi
29 pop esi
30 pop ebx
31 mov esp, ebp
32 pop ebp
33 ret0
34 ?widget@@YAHHH@Z ENDP ; widget
35 _TEXT ENDS
36 PUBLIC ?bar@@YAHHH@Z ; bar
37 EXTRN __RTC_CheckEsp:PROC
38 ; Function compile flags: /Odtp /RTCsu /ZI
39 ; COMDAT ?bar@@YAHHH@Z
40 _TEXT SEGMENT
41 _c$ = -8; size = 4
42 _a$ = 8; size = 4
43 _b$ = 12; size = 4
44 ?bar@@YAHHH@Z PROC ; bar, COMDAT
45
46 ; 9 : {
47
48 push ebp
49 mov ebp, esp
50 sub esp, 204; 000000ccH
51 push ebx
52 push esi
53 push edi
54 lea edi, DWORD PTR [ebp-204]
55 mov ecx, 51; 00000033H
56 mov eax, -858993460; ccccccccH
57 repstosd
58
59 ; 10 : int c = widget(a, b);
60
61 mov eax, DWORD PTR _b$[ebp]
62 push eax
63 mov ecx, DWORD PTR _a$[ebp]
64 push ecx
65 call ?widget@@YAHHH@Z ; widget
66 add esp, 8
67 mov DWORD PTR _c$[ebp], eax
68
69 ; 11 : return c;
70
71 mov eax, DWORD PTR _c$[ebp]
72
73 ; 12 : }
74
75 pop edi
76 pop esi
77 pop ebx
78 add esp, 204; 000000ccH
79 cmp ebp, esp
80 call __RTC_CheckEsp
81 mov esp, ebp
82 pop ebp
83 ret0
84 ?bar@@YAHHH@Z ENDP ; bar
85 _TEXT ENDS
86 PUBLIC ?foo@@YAHHH@Z ; foo
87 ; Function compile flags: /Odtp /RTCsu /ZI
88 ; COMDAT ?foo@@YAHHH@Z
89 _TEXT SEGMENT
90 _c$ = -8; size = 4
91 _a$ = 8; size = 4
92 _b$ = 12; size = 4
93 ?foo@@YAHHH@Z PROC ; foo, COMDAT
94
95 ; 15 : {
96
97 push ebp
98 mov ebp, esp
99 sub esp, 204; 000000ccH
100 push ebx
101 push esi
102 push edi
103 lea edi, DWORD PTR [ebp-204]
104 mov ecx, 51; 00000033H
105 mov eax, -858993460; ccccccccH
106 repstosd
107
108 ; 16 : int c=bar(a, b);
109
110 mov eax, DWORD PTR _b$[ebp]
111 push eax
112 mov ecx, DWORD PTR _a$[ebp]
113 push ecx
114 call ?bar@@YAHHH@Z ; bar
115 add esp, 8
116 mov DWORD PTR _c$[ebp], eax
117
118 ; 17 : return c;
119
120 mov eax, DWORD PTR _c$[ebp]
121
122 ; 18 : }
123
124 pop edi
125 pop esi
126 pop ebx
127 add esp, 204; 000000ccH
128 cmp ebp, esp
129 call __RTC_CheckEsp
130 mov esp, ebp
131 pop ebp
132 ret0
133 ?foo@@YAHHH@Z ENDP ; foo
134 _TEXT ENDS
135 PUBLIC _main
136 ; Function compile flags: /Odtp /RTCsu /ZI
137 ; COMDAT _main
138 _TEXT SEGMENT
139 _main PROC ; COMDAT
140
141 ; 21 : {
142
143 push ebp
144 mov ebp, esp
145 sub esp, 192; 000000c0H
146 push ebx
147 push esi
148 push edi
149 lea edi, DWORD PTR [ebp-192]
150 mov ecx, 48; 00000030H
151 mov eax, -858993460; ccccccccH
152 repstosd
153
154 ; 22 :
155 ; 23 : foo( 1, 2);
156
157 push2
158 push1
159 call ?foo@@YAHHH@Z ; foo
160 add esp, 8
161
162 ; 24 : }
163
164 xor eax, eax
165 pop edi
166 pop esi
167 pop ebx
168 add esp, 192; 000000c0H
169 cmp ebp, esp
170 call __RTC_CheckEsp
171 mov esp, ebp
172 pop ebp
173 ret0
174 _main ENDP
175 _TEXT ENDS
176 END
2 ; COMDAT ?widget@@YAHHH@Z
3 _TEXT SEGMENT
4 _a$ = 8; size = 4
5 _b$ = 12; size = 4
6 ?widget@@YAHHH@Z PROC ; widget, COMDAT
7
8 ; 4 : {
9
10 push ebp
11 mov ebp, esp
12 sub esp, 192; 000000c0H
13 push ebx
14 push esi
15 push edi
16 lea edi, DWORD PTR [ebp-192]
17 mov ecx, 48; 00000030H
18 mov eax, -858993460; ccccccccH
19 repstosd
20
21 ; 5 : return a + b;
22
23 mov eax, DWORD PTR _a$[ebp]
24 add eax, DWORD PTR _b$[ebp]
25
26 ; 6 : }
27
28 pop edi
29 pop esi
30 pop ebx
31 mov esp, ebp
32 pop ebp
33 ret0
34 ?widget@@YAHHH@Z ENDP ; widget
35 _TEXT ENDS
36 PUBLIC ?bar@@YAHHH@Z ; bar
37 EXTRN __RTC_CheckEsp:PROC
38 ; Function compile flags: /Odtp /RTCsu /ZI
39 ; COMDAT ?bar@@YAHHH@Z
40 _TEXT SEGMENT
41 _c$ = -8; size = 4
42 _a$ = 8; size = 4
43 _b$ = 12; size = 4
44 ?bar@@YAHHH@Z PROC ; bar, COMDAT
45
46 ; 9 : {
47
48 push ebp
49 mov ebp, esp
50 sub esp, 204; 000000ccH
51 push ebx
52 push esi
53 push edi
54 lea edi, DWORD PTR [ebp-204]
55 mov ecx, 51; 00000033H
56 mov eax, -858993460; ccccccccH
57 repstosd
58
59 ; 10 : int c = widget(a, b);
60
61 mov eax, DWORD PTR _b$[ebp]
62 push eax
63 mov ecx, DWORD PTR _a$[ebp]
64 push ecx
65 call ?widget@@YAHHH@Z ; widget
66 add esp, 8
67 mov DWORD PTR _c$[ebp], eax
68
69 ; 11 : return c;
70
71 mov eax, DWORD PTR _c$[ebp]
72
73 ; 12 : }
74
75 pop edi
76 pop esi
77 pop ebx
78 add esp, 204; 000000ccH
79 cmp ebp, esp
80 call __RTC_CheckEsp
81 mov esp, ebp
82 pop ebp
83 ret0
84 ?bar@@YAHHH@Z ENDP ; bar
85 _TEXT ENDS
86 PUBLIC ?foo@@YAHHH@Z ; foo
87 ; Function compile flags: /Odtp /RTCsu /ZI
88 ; COMDAT ?foo@@YAHHH@Z
89 _TEXT SEGMENT
90 _c$ = -8; size = 4
91 _a$ = 8; size = 4
92 _b$ = 12; size = 4
93 ?foo@@YAHHH@Z PROC ; foo, COMDAT
94
95 ; 15 : {
96
97 push ebp
98 mov ebp, esp
99 sub esp, 204; 000000ccH
100 push ebx
101 push esi
102 push edi
103 lea edi, DWORD PTR [ebp-204]
104 mov ecx, 51; 00000033H
105 mov eax, -858993460; ccccccccH
106 repstosd
107
108 ; 16 : int c=bar(a, b);
109
110 mov eax, DWORD PTR _b$[ebp]
111 push eax
112 mov ecx, DWORD PTR _a$[ebp]
113 push ecx
114 call ?bar@@YAHHH@Z ; bar
115 add esp, 8
116 mov DWORD PTR _c$[ebp], eax
117
118 ; 17 : return c;
119
120 mov eax, DWORD PTR _c$[ebp]
121
122 ; 18 : }
123
124 pop edi
125 pop esi
126 pop ebx
127 add esp, 204; 000000ccH
128 cmp ebp, esp
129 call __RTC_CheckEsp
130 mov esp, ebp
131 pop ebp
132 ret0
133 ?foo@@YAHHH@Z ENDP ; foo
134 _TEXT ENDS
135 PUBLIC _main
136 ; Function compile flags: /Odtp /RTCsu /ZI
137 ; COMDAT _main
138 _TEXT SEGMENT
139 _main PROC ; COMDAT
140
141 ; 21 : {
142
143 push ebp
144 mov ebp, esp
145 sub esp, 192; 000000c0H
146 push ebx
147 push esi
148 push edi
149 lea edi, DWORD PTR [ebp-192]
150 mov ecx, 48; 00000030H
151 mov eax, -858993460; ccccccccH
152 repstosd
153
154 ; 22 :
155 ; 23 : foo( 1, 2);
156
157 push2
158 push1
159 call ?foo@@YAHHH@Z ; foo
160 add esp, 8
161
162 ; 24 : }
163
164 xor eax, eax
165 pop edi
166 pop esi
167 pop ebx
168 add esp, 192; 000000c0H
169 cmp ebp, esp
170 call __RTC_CheckEsp
171 mov esp, ebp
172 pop ebp
173 ret0
174 _main ENDP
175 _TEXT ENDS
176 END