Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: downloads/boost_1_34_1/more/error_handling.html @ 56

Last change on this file since 56 was 29, checked in by landauf, 16 years ago

updated boost from 1_33_1 to 1_34_1

File size: 11.2 KB
Line 
1<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 3.2//EN">
2
3<html>
4  <head>
5    <meta name="generator" content=
6    "HTML Tidy for Cygwin (vers 1st April 2002), see www.w3.org">
7    <meta http-equiv="Content-Type" content=
8    "text/html; charset=windows-1252">
9
10    <title>Error and Exception Handling</title>
11  </head>
12
13  <body>
14    <h1>Error and Exception Handling</h1>
15
16    <h2>References</h2>
17
18    <p>The following paper is a good introduction to some of the issues of
19    writing robust generic components:</p>
20
21    <blockquote>
22      <a href="generic_exception_safety.html">D. Abrahams: ``Exception Safety
23      in Generic Components''</a>, originally published in <a href=
24      "http://www.springer.de/cgi-bin/search_book.pl?isbn=3-540-41090-2">M.
25      Jazayeri, R. Loos, D. Musser (eds.): Generic Programming, Proc. of a
26      Dagstuhl Seminar, Lecture Notes on Computer Science. Volume. 1766</a>
27    </blockquote>
28
29    <h2>Guidelines</h2>
30
31    <h3>When should I use exceptions?</h3>
32
33    <p>The simple answer is: ``whenever the semantic and performance
34    characteristics of exceptions are appropriate.''</p>
35
36    <p>An oft-cited guideline is to ask yourself the question ``is this an
37    exceptional (or unexpected) situation?'' This guideline has an attractive
38    ring to it, but is usually a mistake. The problem is that one person's
39    ``exceptional'' is another's ``expected'': when you really look at the
40    terms carefully, the distinction evaporates and you're left with no
41    guideline. After all, if you check for an error condition, then in some
42    sense you expect it to happen, or the check is wasted code.</p>
43
44    <p>A more appropriate question to ask is: ``do we want stack
45    unwinding here?'' Because actually handling an exception is likely
46    to be significantly slower than executing mainline code, you
47    should also ask: ``Can I afford stack unwinding here?'' For
48    example, a desktop application performing a long computation might
49    periodically check to see whether the user had pressed a cancel
50    button. Throwing an exception could allow the operation to be
51    cancelled gracefully. On the other hand, it would probably be
52    inappropriate to throw and <i>handle</i> exceptions in the inner
53    loop of this computation because that could have a significant
54    performance impact.  The guideline mentioned above has a grain of
55    truth in it: in time critical code, throwing an exception
56    should <em>be</em> the exception, not the rule.</p>
57
58    <h3>How should I design my exception classes?</h3>
59
60    <ol>
61      <li><b>Derive your exception class
62      from <code>std::exception</code></b>. Except in *very* rare
63      circumstances where you can't afford the cost of a virtual
64      table,
65      <code>std::exception</code> makes a reasonable exception base class,
66      and when used universally, allows programmers to catch "everything"
67      without resorting to <code>catch(...)</code>. For more about
68      <code>catch(...)</code>, see below. 
69
70      <li><b>Use <i>virtual</i> inheritance.</b> This insight is due
71      to Andrew Koenig.  Using virtual inheritance from your
72      exception's base class(es) prevents ambiguity problems at the
73      catch-site in case someone throws an exception derived from
74      multiple bases which have a base class in common:
75
76<pre>
77#include &lt;iostream&gt;
78struct my_exc1 : std::exception { char const* what() const throw(); };
79struct my_exc2 : std::exception { char const* what() const throw(); };
80struct your_exc3 : my_exc1, my_exc2 {};
81
82int main()
83{
84   try { throw your_exc3(); }
85   catch(std::exception const&amp; e) {}
86   catch(...) { std::cout &lt;&lt; &quot;whoops!&quot; &lt;&lt; std::endl; }
87}
88</pre>
89
90The program above prints <code>&quot;whoops&quot;</code> because the
91C++ runtime can't resolve which <code>exception</code> instance to
92match in the first catch clause.
93
94      </li>
95
96      <li>
97        <b><i>Don't</i> embed a std::string object</b> or any other data
98        member or base class whose copy constructor could throw an exception.
99        That could lead directly to std::terminate() at the throw point.
100        Similarly, it's a bad idea to use a base or member whose ordinary
101        constructor(s) might throw, because, though not necessarily fatal to
102        your program, you may report a different exception than intended from
103        a <i>throw-expression</i> that includes construction such as:
104
105        <blockquote>
106<pre>
107throw some_exception();   
108</pre>
109        </blockquote>
110
111        <p>There are various ways to avoid copying string objects when
112        exceptions are copied, including embedding a fixed-length buffer in
113        the exception object, or managing strings via reference-counting.
114        However, consider the next point before pursuing either of these
115        approaches.</p>
116      </li>
117
118      <li><b>Format the <code>what()</code> message on demand</b>, if you
119      feel you really must format the message. Formatting an exception error
120      message is typically a memory-intensive operation that could
121      potentially throw an exception. This is an operation best delayed until
122      after stack unwinding has occurred, and presumably, released some
123      resources. It's a good idea in this case to protect your
124      <code>what()</code> function with a <code>catch(...)</code> block so
125      that you have a fallback in case the formatting code throws</li>
126
127      <li><b>Don't worry <i>too</i> much about the <code>what()</code>
128      message</b>. It's nice to have a message that a programmer stands a
129      chance of figuring out, but you're very unlikely to be able to compose
130      a relevant and <i>user</i>-comprehensible error message at the point an
131      exception is thrown. Certainly, internationalization is beyond the
132      scope of the exception class author. <a href=
133      "../people/peter_dimov.htm">Peter Dimov</a> makes an excellent argument
134      that the proper use of a <code>what()</code> string is to serve as a
135      key into a table of error message formatters. Now if only we could get
136      standardized <code>what()</code> strings for exceptions thrown by the
137      standard library...</li>
138
139      <li><b>Expose relevant information about the cause of the error</b> in
140      your exception class' public interface. A fixation on the
141      <code>what()</code> message is likely to mean that you neglect to
142      expose information someone might need in order to make a coherent
143      message for users. For example, if your exception reports a numeric
144      range error, it's important to have the actual numbers involved
145      available <i>as numbers</i> in the exception class' public interface
146      where error reporting code can do something intelligent with them. If
147      you only expose a textual representation of those numbers in the
148      <code>what()</code> string, you will make life very difficult for
149      programmers who need to do something more (e.g. subtraction) with them
150      than dumb output.</li>
151
152      <li><b>Make your exception class immune to double-destruction</b> if
153      possible. Unfortunately, several popular compilers occasionally cause
154      exception objects to be destroyed twice. If you can arrange for that to
155      be harmless (e.g. by zeroing deleted pointers) your code will be more
156      robust.</li>
157    </ol>
158
159    <h3>What About Programmer Errors?</h3>
160
161    <p>As a developer, if I have violated a precondition of a library I'm
162    using, I don't want stack unwinding. What I want is a core dump or the
163    equivalent - a way to inspect the state of the program at the exact point
164    where the problem was detected. That usually means <tt>assert()</tt> or
165    something like it.</p>
166
167    <p>Sometimes it is necessary to have resilient APIs which can stand up to
168    nearly any kind of client abuse, but there is usually a significant cost
169    to this approach. For example, it usually requires that each object used
170    by a client be tracked so that it can be checked for validity. If you
171    need that sort of protection, it can usually be provided as a layer on
172    top of a simpler API. Beware half-measures, though. An API which promises
173    resilience against some, but not all abuse is an invitation to disaster.
174    Clients will begin to rely on the protection and their expectations will
175    grow to cover unprotected parts of the interface.</p>
176
177    <p><b>Note for Windows developers</b>: unfortunately, the native
178    exception-handling used by most Windows compilers actually throws an
179    exception when you use <tt>assert()</tt>. Actually, this is true of other
180    programmer errors such as segmentation faults and divide-by-zero errors.
181    One problem with this is that if you use JIT (Just In Time) debugging,
182    there will be collateral exception-unwinding before the debugger comes up
183    because <code>catch(...)</code> will catch these not-really-C++
184    exceptions. Fortunately, there is a simple but little-known workaround,
185    which is to use the following incantation:</p>
186
187    <blockquote>
188<pre>
189extern "C" void straight_to_debugger(unsigned int, EXCEPTION_POINTERS*)
190{
191    throw;
192}
193extern "C" void (*old_translator)(unsigned, EXCEPTION_POINTERS*)
194         = _set_se_translator(straight_to_debugger);
195</pre>
196    </blockquote>
197    This technique doesn't work if the SEH is raised from within a catch
198    block (or a function called from within a catch block), but it still
199    eliminates the vast majority of JIT-masking problems.
200
201    <h3>How should I handle exceptions?</h3>
202
203    <p>Often the best way to deal with exceptions is to not handle them at
204    all. If you can let them pass through your code and allow destructors to
205    handle cleanup, your code will be cleaner.</p>
206
207    <h4>Avoid <code>catch(...)</code> when possible</h4>
208    Unfortunately, operating systems other than Windows also wind non-C++
209    "exceptions" (such as thread cancellation) into the C++ EH machinery, and
210    there is sometimes no workaround corresponding to the
211    <code>_set_se_translator</code> hack described above. The result is that
212    <code>catch(...)</code> can have the effect of making some unexpected
213    system notification at a point where recovery is impossible look just
214    like a C++ exception thrown from a reasonable place, invalidating the
215    usual safe assumptions that destructors and catch blocks have taken valid
216    steps to ensure program invariants during unwinding.
217
218    <p>I reluctantly concede this point to Hillel Y. Sims, after many
219    long debates in the newsgroups: until all OSes are "fixed", if
220    every exception were derived from <code>std::exception</code> and
221    everyone substituted
222    <code>catch(std::exception&amp;)</code> for <code>catch(...)</code>, the
223    world would be a better place.</p>
224
225    <p>Sometimes, <code>catch(...)</code>, is still the most appropriate
226    pattern, in spite of bad interactions with OS/platform design choices. If
227    you have no idea what kind of exception might be thrown and you really
228    <i>must</i> stop unwinding it's probably still your best bet. One obvious
229    place where this occurs is at language boundaries.</p>
230    <hr>
231
232    <p>&copy; Copyright David Abrahams 2001-2003. All rights reserved.</p>
233
234    <p>Revised
235    <!--webbot bot="Timestamp" s-type="EDITED" s-format="%d %B, %Y" startspan -->
236     21 August, 2003<!--webbot bot="Timestamp" endspan i-checksum="34359" -->
237    </p>
238  </body>
239</html>
240
Note: See TracBrowser for help on using the repository browser.