summaryrefslogtreecommitdiff
path: root/docs/exceptions.html
blob: 21a578950207ef15e4cc26a47e3b95cfee89404d (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
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
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
<!-- $Id$ -->
<html> <head>
<title>Using ACE try macros for CORBA programming</title>
</head>

  <body>
    <h1>Using ACE try macros for CORBA programming</h1>

    <P>CORBA::Environment provides a way for exception handling when
      native c++ exception handling is unavailable or undesirable.
      However, writing portable code for both (with and without) native
      exception handling capability is very hairy.
    </P>
    <P>ACE provides a set of macros to help dealing with the chaos,
      but please keep in mind that no amount of macros is going to
      solve the problem perfectly.
    </P>

<h3>In a Nutshell</h3>

    <P>This section explains some simple rules of writing programs for
      platforms with and without native exception support using ACE's
      try macros.
    </P>

    <ol>
      <li><P><em>Name of CORBA::Environment variable</em><br>
          A function that may throw a CORBA::Exception needs a
          CORBA::Environment variable to pass up exceptions and to gather
          exceptions from functions it called.  By default, ACE try macros
          assume the variable is named <code>ACE_TRY_ENV</code>.
          <code>ACE_TRY_ENV</code> itself is also a macro which can be
          redefined.  If you are using TAO, more likely than not, you
          don't have to worry about redefining this macro because TAO
          is written to use ACE try macros.  For example, you should
          define your functions as,
        </P>
        <pre>
      int AN_OBJ::foobar (int a, int b, CORBA_Environment &ACE_TRY_ENV);
        </pre>
        <P>
          and within the function, call other functions that might throw
          exceptions like,
        </P>
        <pre>
      another_obj->func_name (x, y, ACE_TRY_ENV);
        </pre>

        <P>
          As mentioned, you can redefine the name of the variable to
          something else to avoid name clashing.  Alternatively, there's
          another macro (<code>ACE_ADOPT_CORBA_ENV</code>) that allow you
          to use another variable name as the default CORBA::Environment
          <em>within</em> a function.
        </P>
      </LI>

      <li><P><em>Throwing exceptions:</em><br>
          Use <code>ACE_THROW</code> and <code>ACE_THROW_RETURN</code> to
          throw exceptions.  They should never be used withing a try
          block; please use <code>ACE_TRY_THROW</code> instead.
        </P>
      </LI

      <li><P><em>Propagating exceptions:</em><br>
          To simulate native exceptions on platforms without native
          exception handling, <em>every</em> single function call that may
          throw exceptions must be followed by <code>ACE_CHECK</code> or
          <code>ACE_CHECK_RETURN</code>.  Notice that you should always
          follow the outter most <code>ACE_ENDTRY</code> with
          <code>ACE_CHECK</code> or <code>ACE_CHECK_RETURN</code> because
          there might be uncaught exception.
        </p>

        <P>You should pass <code>ACE_TRY_ENV</code> to these
          functions.
        </p>

        <P>Be very careful not to combine exception throwing functions
          in one statement like this:
        </P>
        <pre>
          x = obj1->callme (ACE_TRY_ENV) + obj2->dare_me (ACE_TRY_ENV);
          ACE_CHECK;
        </pre>
        <P>This example may work differently when native exception
          handling is enabled/disabled.
        </p>
      </LI>

      <li><P><em>Catching exceptions:</em><br>
          Use <code>ACE_TRY</code> to catch exceptions if there's an
          <code>ACE_TRY_ENV</code> available.  Otherwise, use
          <code>ACE_TRY_NEW_ENV</code>.  If there are more than one try
          blocks in a function, use <code>ACE_TRY_EX</code> for all
          subsequence try blocks to avoid name clashing of labels.
        </p>
        <ul>
          <li><P>Within a <code>ACE_TRY</code> block, use the variable
              <code>ACE_TRY_ENV</code> to pass down the
              <code>CORBA_Environment</code> (see <a
                href="#try_env">this</a> example.)
            </p>
          </LI>

          <li><P>Follow <em>every</em> exception throwing function with
              <code>ACE_TRY_CHECK</code>, including inner
              <code>ACE_ENDTRY</code>.
            </p>
          </LI>

          <li><P>Use <code>ACE_CATCH</code> to catch exceptions of certain
              type.
            </p>
          </LI>

          <li><P><code>ACE_CATCHANY</code> catches <em>any</em> exceptions
              of type <code>CORBA_Exception</code>.
            </p>
          </LI>

          <li><P>Use <code>ACE_RETHROW</code> to rethrow the same exception
              within a <code>ACE_CATCH</code> or
              <code>ACE_CATCHANY</code> block.
            </p>
          </LI>

          <li><P>A <code>ACE_TRY</code> block must be terminated with
              a <code>ACE_ENDTRY</code> statement.
            </p>
          </LI>

          <li><P>Throw an exception within a <code>ACE_TRY</code>
              block or <code>ACE_CATCH</code> block using
              <a href="#try_throw"><code>ACE_TRY_THROW</code></a>.
            </p>
          </LI>
      </LI>
    </ul>
    </ol>

<h3>Examples</h3>

Refer to <a href="../ace/CORBA_macros.h"><code>
$ACE_ROOT/ace/CORBA_macros.h</code></a> for complete definitions of
macros discussed here.

<ul>Sample exception catching:
<pre>
      ACE_TRY
        {
          some_operation (arg1, arg2, ACE_TRY_ENV);
          ACE_TRY_CHECK;

          .
          .
          if (whatever)
            ACE_TRY_THROW (CORBA::BadParam);

          some_other_operation (arg1, arg2, arg3, ACE_TRY_ENV);
          ACE_TRY_CHECK;
        }
      ACE_CATCH (CORBA_some_exception, ex)
        {
          // error handling.
          if (still_has_error)
            ACE_TRY_THROW (CORBA::NOWAY);
        }
      ACE_CATCHANY
        {
          // error handling.
          // then rethow the exception.
          ACE_RETHROW;
        }
      ACE_ENDTRY;
      ACE_CHECK;
</pre><br>

  <li><code>ACE_TRY</code> and also declares a label (so do
      <code>ACE_TRY_NEW_ENV</code>.  To avoid defining the
      same label multiple times within a function, use
      <code>ACE_TRY_EX</code> with different labels for different try
      blocks instead.  For example,<br>

<pre>
      ACE_TRY_EX (block_1)
        {
          some_operation (arg1, arg2, ACE_TRY_ENV);
          ACE_TRY_CHECK_EX (block_1);

          some_other_operation (arg1, arg2, arg3, ACE_TRY_ENV);
          ACE_TRY_CHECK_EX (block_1);
        }
      ACE_CATCH (CORBA_some_exception, ex)
        {
          // error handling.
        }
      ACE_CATCHANY
        {
          // error handling.
        }
      ACE_ENDTRY;
      ACE_CHECK_RETURN (-1);

      // Some other operation here
      //       .
      //       .
      //       .
      //       .

      ACE_TRY_EX (block_2)
        {
          foo (arg, ACE_TRY_ENV);
          ACE_TRY_CHECK_EX (block_2);

          bar (arg1, arg2, ACE_TRY_ENV);
          ACE_TRY_CHECK_EX (block_2);
        }
      ACE_CATCH (CORBA_some_exception, ex)
        {
          // error handling.
        }
      ACE_CATCHANY
        {
          // error handling.
        }
      ACE_ENDTRY;
      ACE_CHECK_RETURN (-1);
</pre><p>

  <li>Be <em>VERY</em> wary of <code>ACE_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>Instead of depending on <code>ACE_CATCHALL</code>, use
      <code>auto_prt</code> style mechanism to prevent memory leaks
      from exceptions.<p>
</ul>

<h3>General Guidelines of Exceptions</h3>
<ul>
  <li>Don't catch an exception just to rethrow it.  Exceptions cost
      you performance.<p>

  <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>
      ACE_TRY
        {
            obj[i++] = foo_bar_method (a, b, ACE_TRY_ENV);
        }
</pre><p>

  <li>Make sure an exception doesn't cause resource leak (memory,
      socket, ...) (hint: Use auto_ptr to avoid memory leak,
        and ACE_Guard for locks.)<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>

<H3>Caveats</H3>

    <P>As we already mentioned no set of macros can cover all cases
      and preserve the semantics between native C++ exceptions and the
      <CODE>CORBA::Environment</CODE> based mapping.
      Some of the problems that our macros are described below:
    <P>

    <UL>
      <LI><P>Using the macros in loops can produce problems with
          <CODE>break</CODE> and <CODE>continue</CODE> statements, for
          example:
        </P>
        <PRE>
for (int i = 0; i < 10; ++i)
{
  ACE_TRY
    {
      if (x[i] == 0)
        continue; // will *not* work
      if (x[i] == -1)
        break; // will *not* work either
    }
  ACE_CATCH (CORBA::Exception, ex)
    {
    }
  ACE_ENDTRY;
}
</PRE>
    </UL>


</ul>
<!--#include virtual="/~schmidt/cgi-sig.html" -->
</body></HTML>