error_handling.html 11 KB

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