1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
|
<!DOCTYPE HTML SYSTEM
"http://www.w3.org/pub/WWW/MarkUp/Cougar/Cougar.dtd">
<!-- $Id$ -->
<html> <head>
<title>Writing exception safe codes</title>
</head>
<body>
<h1>Writing exception safe codes</h1>
TAO can be use on platforms with/without native exception support.
However, there are certain guidelines that need to be followed in
order for it to work on both platforms.
<h3>In a Nutshell</h3>
This section explains some simple rules of writing programs for
platforms with and without native exception support using TAO's try
macros.
<ol>
<li><em>Function definition:</em><br>
A function that throws exceptions or calls other exception
throwing functions must have an argument of reference of
<code>CORBA_Environment</code> for exceptions be passed back
thru it. This arguemnt should <em>always</em> be named
<code>TAO_IN_ENV</code> (which means the passed in environment,)
and has a default value of
<code>CORBA_Environment::default_environment ()</code>. For
example,<p>
<pre>
int foobar (int a, int b, CORBA_Environment &TAO_IN_ENV =
CORBA_Environment::default_environment);
</pre><p>
<li><em>Throwing exceptions:</em><br>
Use <code>TAO_THROW</code> and <code>TAO_THROW_RETURN</code> to
throw exceptions.
<li><em>Propagating exceptions:</em><br>
To simulate native exceptions on platforms without native
exceptions, <em>every</em> single function call that may throw
exceptions must be followed by <code>TAO_CHECK_RETURN</code> or
<code>TAO_CHECK_RETURN_VOID</code>.<p>
You should pass <code>TAO_IN_ENV</code> to these functions.<p>
Be very careful not to combine calls to several exception
throwing functions in one statement.<p>
<li><em>Catching exceptions:</em><br>
Use <code>TAO_TRY</code> and buddies to catch exceptions.<p>
<ul>
<li>Within a <code>TAO_TRY</code> block, use the variable
<code>TAO_TRY_ENV</code> to pass down the
<code>CORBA_Environment</code> (see <a
href="#try_env">this</a> example.) <p>
<li>Follow <em>every</em> exception throwing function with
<code>TAO_CHECK_ENV</code>. <p>
<li>Use <code>TAO_CATCH</code> to catch exceptions of certain
type. <p>
<li><code>TAO_CATCHANY</code> catches <em>any</em> exceptions
of type <code>CORBA_Exception</code>.<p>
<li>Use <code>TAO_RETHROW</code> to rethrow the same exception
within a <code>TAO_CATCH</code> or
<code>TAO_CATCHANY</code> block.<p>
<li>A <code>TAO_TRY</code> block must be terminated with a
<code>TAO_ENDTRY</code> statement.<p>
<li>Throw an exception within a <code>TAO_TRY</code> block
using <a href="#try_throw"><code>TAO_TRY_THROW</code></a><p>
<li>Notice that at the moment, <code>TAO_TRY</code> macros do
not propogate the exception up if one is not caught.<p>
</ul><p>
<li>Avoid using macros that require to specify the environment used
like, <code>TAO_THROW_ENV_RETURN</code>,
<code>TAO_CHECK_ENV_RETURN</code> and so on. They will be
depricated in the future.
</ol>
<h3>Details</h3>
Refer to <code>$TAO_ROOT/tao/try_macros.h</code> for complete
definitions of macros discussed here.
<ul>
<li>Use <code>TAO_THROW</code>, <code>TAO_THROW_ENV</code>,
<code>TAO_THROW_RETURN</code>, <code>TAO_THROW_ENV_RETURN</code>
to throw exceptions. <code>TAO_THROW</code> and
<code>TAO_THROW_RETURN</code> assume that the name of the
<code>CORBA_Environment</code> variable used to pass back the
exception is called <code>_env</code>. Use
<code>TAO_THROW_ENV</code> and <code>TAO_THROW_ENV_RETURN</code>
to pass back thru the <code>CORBA_Environment</code> variable
specified. (Also see: <a href="#try_throw">Throwing exceptions
within try blocks.</a>)<p>
<li><a name="try_env"></a>Use <code>TAO_TRY</code>,
<code>TAO_CHECK_ENV</code>, <code>TAO_CATCH</code>,
<code>TAO_CATCHANY</code>, and <code>TAO_ENDTRY</code>
macros. For example:<br>
<pre>
TAO_TRY
{
some_operation (arg1, arg2, TAO_TRY_ENV);
TAO_CHECK_ENV;
some_other_operation (arg1, arg2, arg3, TAO_TRY_ENV);
TAO_CHECK_ENV;
}
TAO_CATCH (CORBA_some_exception, ex)
{
// error handling.
}
TAO_CATCHANY
{
// error handling.
}
TAO_ENDTRY;
</pre><br>
Since a lot of compilers/platforms still don't handle native
exceptions correctly, TAO doesn't use exceptions on these
platforms and tend to check the returning environment. When
these programs move to platforms that support native exceptions,
they stop working.<p>
<li><code>TAO_TRY</code> defines a new
<code>CORBA_Environment</code> called TAO_TRY_ENV and use it to
pass down the functions it guards against. If you want to reuse
the <code>CORBA_Environment</code> that's alreday defined in the
scope <code>TAO_TRY</code> resides, you can use
<code>TAO_TRY_VAR</code> to achieve that.<p>
<li><code>TAO_TRY</code> also declares a label. To avoid defining the
same label multiple times within a function, use
<code>TAO_TRY_EX</code>, <code>TAO_CHECK_ENV_EX</code> with
different labels for different try blocks instead. For
example,<br>
<pre>
TAO_TRY_EX (block_1)
{
some_operation (arg1, arg2, TAO_TRY_ENV);
TAO_CHECK_ENV_EX (block_1);
some_other_operation (arg1, arg2, arg3, TAO_TRY_ENV);
TAO_CHECK_ENV_EX (block_1);
}
TAO_CATCH (CORBA_some_exception, ex)
{
// error handling.
}
TAO_CATCHANY
{
// error handling.
}
TAO_ENDTRY;
// Some other operation here
// .
// .
// .
// .
TAO_TRY_EX (block_2)
{
foo (arg, TAO_TRY_ENV);
TAO_CHECK_ENV_EX (block_2);
bar (arg1, arg2, TAO_TRY_ENV);
TAO_CHECK_ENV_EX (block_2);
}
TAO_CATCH (CORBA_some_exception, ex)
{
// error handling.
}
TAO_CATCHANY
{
// error handling.
}
TAO_ENDTRY;
</pre><p>
<a name="try_throw"></a>
<li>Notice that you need to use <code>TAO_TRY_THROW</code> and
<code>TAO_TRY_THROW_EX</code> when throwing exceptions within
the try block. Without using it, the exception won't be caught
by the try block, which is not how native exceptions work.<p>
<li>Follow each operation that may throw an exception with
<code>TAO_CHECK_ENV</code> or <code>TAO_CHECK_ENV_EX</code>.
This is required for simulated exceptions to break out of
current flow of control into <code>TAO_CATCH</code>
sections. Although it is not required to put an
<code>TAO_CHECK_ENV</code> or an <code>TAO_CHECK_ENV_EX</code>
after the last operation, it is much cleaner to always put it
there and avoid further errors when you need add more stuff
after that.<p>
<li>TAO functions use a <code>CORBA_Environment</code> argument to
pass in/out the simulated exceptions. By default, this argument
is named "<code>_env</code>" (which is what TAO_IDL generated
code uses.) Use <code>TAO_THROW</code> or
<code>TAO_THROW_RETURN</code> to throw an exception. However,
if a function uses a different name to pass back the CORBA
environment, you'll need to use <code>TAO_THROW_ENV</code> or
<code>TAO_THROW_ENV_RETURN</code> and specify the name of the
variable used to pass back the CORBA environment.<p>
<li>To rethrow an exception after catching it, use
<code>TAO_RETHROW_RETURN</code> or
<code>TAO_RETHROW_RETURN_VOID</code>. But if you are reusing
the same <code>CORBA::Environment</code> variable of the
function in the try block, use
<code>TAO_RETHROW_SAME_ENV_RETURN</code> and
<code>TAO_RETHROW_SAME_ENV_RETURN_VOID</code> instead.<p>
<li>Follow each statement that throws exceptions with
<code>TAO_CHECK_ENV_RETURN</code>,
<code>TAO_CHECK_ENV_RETURN_VOID</code> when these exceptions are
not to be caught in the current subroutine. Likewise,
<code>TAO_CHECK_ENV_PRINT_RETURN</code> and
<code>TAO_CHECK_ENV_PRINT_RETURN_VOID</code> pass back an
exception after printing out the content. Notice that the
printing will not work on platforms where native exceptions are
supported. If you have to print out exceptions, you <em>have
to</em> catch them. All these macros cannot and should not be
used in a <code>TRY</code> block.<p>
<li><code>TAO_GUARD_THROW</code>,
<code>TAO_GUARD_THROW_RETURN</code>,
<code>TAO_READ_GUARD_THROW</code>,
<code>TAO_READ_GUARD_THROW_RETURN</code>,
<code>TAO_WRITE_GUARD_THROW</code>, and
<code>TAO_WRITE_GUARD_THROW_RETURN</code> try to acquire a lock
and throw the specified exception when it fails to acquire the
lock.<p>
<li>Notice that <code>TAO_CATCHANY</code> catches <em>any</em>
<code>CORBA_Exception</code> or its subclasses. This limited
catch behavior makes TAO programs behave the same on platforms
with or without native exceptions. If there're needs to catch
all native exceptions in your program, use
<code>TAO_CATCHALL</code> instead. <p>
<li>Be <em>VERY</em> wary of <code>TAO_CATCHALL</code>. It catches
exceptions of any type. If your program depends on it, then,
more often than not, there're something wrong with it.<p>
<li>Use <code>auto_prt</code> type mechanism to prevent memory leaks
from exceptions.<p>
<li>Don't catch an exception just to rethrow it. Exceptions cost
you performance.<p>
<li>Current implementation of <code>TAO_TRY/TAO_CATCH</code> macros
do not propagate a exception up if it is not caught. (So,
you'll have to catch all exceptions with a
<code>TAO_CATCHANY</code> and rethrow it, which contradicts the
previous guideline. ;( )<p>
</ul>
<h2>TO-DO</h2>
<ol>
<li>Automatic rethrow simpulated exceptions if not caught?
<li>must check if the same exception can be caught twice on
compilers without c++ exceptions.
</ol>
<h3>General Guidelines of Exceptions</h3>
<ul>
<li>When exceptions occur, make sure an object's is still in
a valid state or change to a state that can be safely
destructed.<p>
<li>Watch out for side effect in the expression which may cause
exceptions. In the following example, what should
<code>i</code> be if an exception does occur?<br>
<pre>
TAO_TRY
{
obj[i++] = foo_bar_method (a, b, TAO_TRY_ENV);
}
</pre><p>
<li>Make sure an exception doesn't cause resource leak (memory,
socket, ...) (hint: Use auto_ptr to avoid memory leak.)<p>
<li>Don't catch any exception that you don't know how to handle.<p>
<li>Never throw an exception from destructor (unless you know what
it implies.)<p>
<li>Use exceptions to provide more information about the error.<p>
<li>Rethrow a different exception only to provide <em>more</em>
information. Do not catch an exception just to rethrow, say,
<code>unknow_exception</code>.<p>
</ul>
<!--#include virtual="/~schmidt/cgi-sig.html" -->
</body></HTML>
|