summaryrefslogtreecommitdiff
path: root/more/error_handling.html
blob: 14364048f5b3f6e6dd293b422f789e51bfc09c87 (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
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 3.2//EN">

<html>
  <head>
    <meta name="generator" content=
    "HTML Tidy for Cygwin (vers 1st April 2002), see www.w3.org">
    <meta http-equiv="Content-Type" content=
    "text/html; charset=windows-1252">

    <title>Error and Exception Handling</title>
  </head>

  <body>
    <h1>Error and Exception Handling</h1>

    <h2>References</h2>

    <p>The following paper is a good introduction to some of the issues of
    writing robust generic components:</p>

    <blockquote>
      <a href="generic_exception_safety.html">D. Abrahams: ``Exception Safety
      in Generic Components''</a>, originally published in <a href=
      "http://www.springer.de/cgi-bin/search_book.pl?isbn=3-540-41090-2">M.
      Jazayeri, R. Loos, D. Musser (eds.): Generic Programming, Proc. of a
      Dagstuhl Seminar, Lecture Notes on Computer Science. Volume. 1766</a>
    </blockquote>

    <h2>Guidelines</h2>

    <h3>When should I use exceptions?</h3>

    <p>The simple answer is: ``whenever the semantic and performance
    characteristics of exceptions are appropriate.''</p>

    <p>An oft-cited guideline is to ask yourself the question ``is this an
    exceptional (or unexpected) situation?'' This guideline has an attractive
    ring to it, but is usually a mistake. The problem is that one person's
    ``exceptional'' is another's ``expected'': when you really look at the
    terms carefully, the distinction evaporates and you're left with no
    guideline. After all, if you check for an error condition, then in some
    sense you expect it to happen, or the check is wasted code.</p>

    <p>A more appropriate question to ask is: ``do we want stack
    unwinding here?'' Because actually handling an exception is likely
    to be significantly slower than executing mainline code, you
    should also ask: ``Can I afford stack unwinding here?'' For
    example, a desktop application performing a long computation might
    periodically check to see whether the user had pressed a cancel
    button. Throwing an exception could allow the operation to be
    cancelled gracefully. On the other hand, it would probably be
    inappropriate to throw and <i>handle</i> exceptions in the inner
    loop of this computation because that could have a significant
    performance impact.  The guideline mentioned above has a grain of
    truth in it: in time critical code, throwing an exception
    should <em>be</em> the exception, not the rule.</p>

    <h3>How should I design my exception classes?</h3>

    <ol>
      <li><b>Derive your exception class
      from <code>std::exception</code></b>. Except in *very* rare
      circumstances where you can't afford the cost of a virtual
      table,
      <code>std::exception</code> makes a reasonable exception base class,
      and when used universally, allows programmers to catch "everything"
      without resorting to <code>catch(...)</code>. For more about
      <code>catch(...)</code>, see below.  

      <li><b>Use <i>virtual</i> inheritance.</b> This insight is due
      to Andrew Koenig.  Using virtual inheritance from your
      exception's base class(es) prevents ambiguity problems at the
      catch-site in case someone throws an exception derived from
      multiple bases which have a base class in common:

<pre>
#include &lt;iostream&gt;
struct my_exc1 : std::exception { char const* what() const throw(); };
struct my_exc2 : std::exception { char const* what() const throw(); };
struct your_exc3 : my_exc1, my_exc2 {};

int main()
{
   try { throw your_exc3(); }
   catch(std::exception const&amp; e) {}
   catch(...) { std::cout &lt;&lt; &quot;whoops!&quot; &lt;&lt; std::endl; }
}
</pre>

The program above prints <code>&quot;whoops&quot;</code> because the
C++ runtime can't resolve which <code>exception</code> instance to
match in the first catch clause.

      </li>

      <li>
        <b><i>Don't</i> embed a std::string object</b> or any other data
        member or base class whose copy constructor could throw an exception.
        That could lead directly to std::terminate() at the throw point.
        Similarly, it's a bad idea to use a base or member whose ordinary
        constructor(s) might throw, because, though not necessarily fatal to
        your program, you may report a different exception than intended from
        a <i>throw-expression</i> that includes construction such as: 

        <blockquote>
<pre>
throw some_exception();    
</pre>
        </blockquote>

        <p>There are various ways to avoid copying string objects when
        exceptions are copied, including embedding a fixed-length buffer in
        the exception object, or managing strings via reference-counting.
        However, consider the next point before pursuing either of these
        approaches.</p>
      </li>

      <li><b>Format the <code>what()</code> message on demand</b>, if you
      feel you really must format the message. Formatting an exception error
      message is typically a memory-intensive operation that could
      potentially throw an exception. This is an operation best delayed until
      after stack unwinding has occurred, and presumably, released some
      resources. It's a good idea in this case to protect your
      <code>what()</code> function with a <code>catch(...)</code> block so
      that you have a fallback in case the formatting code throws</li>

      <li><b>Don't worry <i>too</i> much about the <code>what()</code>
      message</b>. It's nice to have a message that a programmer stands a
      chance of figuring out, but you're very unlikely to be able to compose
      a relevant and <i>user</i>-comprehensible error message at the point an
      exception is thrown. Certainly, internationalization is beyond the
      scope of the exception class author. <a href=
      "../people/peter_dimov.htm">Peter Dimov</a> makes an excellent argument
      that the proper use of a <code>what()</code> string is to serve as a
      key into a table of error message formatters. Now if only we could get
      standardized <code>what()</code> strings for exceptions thrown by the
      standard library...</li>

      <li><b>Expose relevant information about the cause of the error</b> in
      your exception class' public interface. A fixation on the
      <code>what()</code> message is likely to mean that you neglect to
      expose information someone might need in order to make a coherent
      message for users. For example, if your exception reports a numeric
      range error, it's important to have the actual numbers involved
      available <i>as numbers</i> in the exception class' public interface
      where error reporting code can do something intelligent with them. If
      you only expose a textual representation of those numbers in the
      <code>what()</code> string, you will make life very difficult for
      programmers who need to do something more (e.g. subtraction) with them
      than dumb output.</li>

      <li><b>Make your exception class immune to double-destruction</b> if
      possible. Unfortunately, several popular compilers occasionally cause
      exception objects to be destroyed twice. If you can arrange for that to
      be harmless (e.g. by zeroing deleted pointers) your code will be more
      robust.</li>
    </ol>

    <h3>What About Programmer Errors?</h3>

    <p>As a developer, if I have violated a precondition of a library I'm
    using, I don't want stack unwinding. What I want is a core dump or the
    equivalent - a way to inspect the state of the program at the exact point
    where the problem was detected. That usually means <tt>assert()</tt> or
    something like it.</p>

    <p>Sometimes it is necessary to have resilient APIs which can stand up to
    nearly any kind of client abuse, but there is usually a significant cost
    to this approach. For example, it usually requires that each object used
    by a client be tracked so that it can be checked for validity. If you
    need that sort of protection, it can usually be provided as a layer on
    top of a simpler API. Beware half-measures, though. An API which promises
    resilience against some, but not all abuse is an invitation to disaster.
    Clients will begin to rely on the protection and their expectations will
    grow to cover unprotected parts of the interface.</p>

    <p><b>Note for Windows developers</b>: unfortunately, the native
    exception-handling used by most Windows compilers actually throws an
    exception when you use <tt>assert()</tt>. Actually, this is true of other
    programmer errors such as segmentation faults and divide-by-zero errors.
    One problem with this is that if you use JIT (Just In Time) debugging,
    there will be collateral exception-unwinding before the debugger comes up
    because <code>catch(...)</code> will catch these not-really-C++
    exceptions. Fortunately, there is a simple but little-known workaround,
    which is to use the following incantation:</p>

    <blockquote>
<pre>
extern "C" void straight_to_debugger(unsigned int, EXCEPTION_POINTERS*)
{
    throw;
}
extern "C" void (*old_translator)(unsigned, EXCEPTION_POINTERS*)
         = _set_se_translator(straight_to_debugger);
</pre>
    </blockquote>
    This technique doesn't work if the SEH is raised from within a catch
    block (or a function called from within a catch block), but it still
    eliminates the vast majority of JIT-masking problems. 

    <h3>How should I handle exceptions?</h3>

    <p>Often the best way to deal with exceptions is to not handle them at
    all. If you can let them pass through your code and allow destructors to
    handle cleanup, your code will be cleaner.</p>

    <h4>Avoid <code>catch(...)</code> when possible</h4>
    Unfortunately, operating systems other than Windows also wind non-C++
    "exceptions" (such as thread cancellation) into the C++ EH machinery, and
    there is sometimes no workaround corresponding to the
    <code>_set_se_translator</code> hack described above. The result is that
    <code>catch(...)</code> can have the effect of making some unexpected
    system notification at a point where recovery is impossible look just
    like a C++ exception thrown from a reasonable place, invalidating the
    usual safe assumptions that destructors and catch blocks have taken valid
    steps to ensure program invariants during unwinding. 

    <p>I reluctantly concede this point to Hillel Y. Sims, after many
    long debates in the newsgroups: until all OSes are "fixed", if
    every exception were derived from <code>std::exception</code> and
    everyone substituted
    <code>catch(std::exception&amp;)</code> for <code>catch(...)</code>, the
    world would be a better place.</p>

    <p>Sometimes, <code>catch(...)</code>, is still the most appropriate
    pattern, in spite of bad interactions with OS/platform design choices. If
    you have no idea what kind of exception might be thrown and you really
    <i>must</i> stop unwinding it's probably still your best bet. One obvious
    place where this occurs is at language boundaries.</p>
    <hr>

    <p>&copy; Copyright David Abrahams 2001-2003. All rights reserved.</p>

    <p>Revised 
    <!--webbot bot="Timestamp" s-type="EDITED" s-format="%d %B, %Y" startspan -->
     21 August, 2003<!--webbot bot="Timestamp" endspan i-checksum="34359" -->
    </p>
  </body>
</html>