summaryrefslogtreecommitdiff
path: root/TAO/docs/exceptions.html
blob: 4b7c39cd0542fe1bfbf1bbe210f2458463f8479a (plain)
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
<!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>Basics</h3>

Refer to <code>$TAO_ROOT/tao/try_macros.h</code> for detail
definition 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>Use <code>TAO_TRY</code>, <code>TAO_CHECK_ENV</code>,
      <code>TAO_CATCH</code>, <code>TAO_CATCHALL</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>Be <em>VERY</em> wary of <code>TAO_CATCHANY</code>.  On
      platforms that use simulated exceptions, it catches any CORBA
      exceptions passed back by an operation.  However, on platforms
      that support native c++ exceptions, <code>TAO_CATCHANY</code>
      translates to <code>catch (...)</code> which catches
      <em>any</em> c++ exception.  Under some circumstances (e.g., the
      <code>CATCHANY</code> block only performs resource clean-up for
      the current activation record,) this may be okay.  But for other
      cases, <code>CATCHANY</code> may accidentally deal with the
      wrong exception.  This is especially true if you are working on
      the internal of TAO.  A reasonable alternative in this case will
      be to catch "CORBA_Exception" class.  For this reason, when
      building non-release version programs on
      platforms that support c++ native exceptions,
      <code>TAO_CATCHANY</code> is replaced with a catch clause to
      catch an exception that'll never happen. <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>We need a new macro that support <code>nothrow new</code>.
</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>