error_handling.html 10.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  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 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 unwinding
  34. here?'' Because actually handling an exception is likely to be
  35. significantly slower than executing mainline code, you should also ask:
  36. ``Can I afford stack unwinding here?'' For example, a desktop application
  37. performing a long computation might periodically check to see whether the
  38. user had pressed a cancel button. Throwing an exception could allow the
  39. operation to be cancelled gracefully. On the other hand, it would
  40. probably be inappropriate to throw and <i>handle</i> exceptions in the
  41. inner loop of this computation because that could have a significant
  42. performance impact.</p>
  43. <h3>How should I design my exception classes?</h3>
  44. <ol>
  45. <li><b>Inherit from <code>std::exception</code></b>. Except in *very*
  46. rare circumstances where you can't afford the cost of a virtual table,
  47. <code>std::exception</code> makes a reasonable exception base class,
  48. and when used universally, allows programmers to catch "everything"
  49. without resorting to <code>catch(...)</code>. For more about
  50. <code>catch(...)</code>, see below.</li>
  51. <li>
  52. <b><i>Don't</i> embed a std::string object</b> or any other data
  53. member or base class whose copy constructor could throw an exception.
  54. That could lead to termination during stack unwinding. Similarly,
  55. it's a bad idea to use a base or member whose ordinary constructor
  56. might throw, because, though not fatal, you will report a different
  57. exception than intended when that happens in a
  58. <i>throw-expression</i> such as:
  59. <blockquote>
  60. <pre>
  61. throw some_exception();
  62. </pre>
  63. </blockquote>
  64. <p>There are various ways to avoid copying string objects when
  65. exceptions are copied, including embedding a fixed-length buffer in
  66. the exception object, or managing strings via reference-counting.
  67. However, consider the next point before pursuing either of these
  68. approaches.</p>
  69. </li>
  70. <li><b>Format the <code>what()</code> message on demand</b>, if you
  71. feel you really must format the message. Formatting an exception error
  72. message is typically a memory-intensive operation that could
  73. potentially throw an exception. This is an operation best delayed until
  74. after stack unwinding has occurred, and presumably, released some
  75. resources. It's a good idea in this case to protect your
  76. <code>what()</code> function with a <code>catch(...)</code> block so
  77. that you have a fallback in case the formatting code throws</li>
  78. <li><b>Don't worry <i>too</i> much about the <code>what()</code>
  79. message</b>. It's nice to have a message that a programmer
  80. stands a chance of figuring out, but you're very unlikely to be
  81. able to compose a relevant and <i>user</i>-comprehensible error
  82. message at the point an exception is thrown. Certainly,
  83. internationalization is beyond the scope of the exception class
  84. author. <a href=
  85. "../people/peter_dimov.htm">Peter Dimov</a> makes an excellent
  86. argument that the proper use of a <code>what()</code> string is
  87. to serve as a key into a table of error message formatters. Now
  88. if only we could get standardized <code>what()</code> strings
  89. for exceptions thrown by the standard library...</li>
  90. <li><b>Expose relevant information about the cause of the
  91. error</b> in your exception class' public interface. A fixation
  92. on the <code>what()</code> message is likely to mean that you
  93. neglect to expose information someone might need in order to
  94. make a coherent message for users. For example, if your
  95. exception reports a numeric range error, it's important to have
  96. the actual numbers involved available <i>as numbers</i> in the
  97. exception class' public interface where error reporting code can
  98. do something intelligent with them. If you only expose a
  99. textual representation of those numbers in
  100. the <code>what()</code> string, you will make life very
  101. difficult for programmers who need to do something more
  102. (e.g. subtraction) with them than dumb output.
  103. <li><b>Make your exception class immune to double-destruction</b> if
  104. possible. Unfortunately, several popular compilers occasionally cause
  105. exception objects to be destroyed twice. If you can arrange for that to
  106. be harmless (e.g. by zeroing deleted pointers) your code will be more
  107. robust.</li>
  108. </ol>
  109. <h3>What About Programmer Errors?</h3>
  110. <p>As a developer, if I have violated a precondition of a library I'm
  111. using, I don't want stack unwinding. What I want is a core dump or the
  112. equivalent - a way to inspect the state of the program at the exact point
  113. where the problem was detected. That usually means <tt>assert()</tt> or
  114. something like it.</p>
  115. <p>Sometimes it is neccessary to have resilient APIs which can stand up
  116. to nearly any kind of client abuse, but there is usually a significant
  117. cost to this approach. For example, it usually requires that each object
  118. used by a client be tracked so that it can be checked for validity. If
  119. you need that sort of protection, it can usually be provided as a layer
  120. on top of a simpler API. Beware half-measures, though. An API which
  121. promises resilience against some, but not all abuse is an invitation to
  122. disaster. Clients will begin to rely on the protection and their
  123. expectations will grow to cover unprotected parts of the interface.</p>
  124. <p><b>Note for Windows developers</b>: unfortunately, the native
  125. exception-handling used by most Windows compilers actually throws an
  126. exception when you use <tt>assert()</tt>. Actually, this is true of other
  127. programmer errors such as segmentation faults and divide-by-zero errors.
  128. One problem with this is that if you use JIT (Just In Time) debugging,
  129. there will be collateral exception-unwinding before the debugger comes up
  130. because <code>catch(...)</code> will catch these not-really-C++
  131. exceptions. Fortunately, there is a simple but little-known workaround,
  132. which is to use the following incantation:</p>
  133. <blockquote>
  134. <pre>
  135. extern "C" void straight_to_debugger(unsigned int, EXCEPTION_POINTERS*)
  136. {
  137. throw;
  138. }
  139. extern "C" void (*old_translator)(unsigned, EXCEPTION_POINTERS*)
  140. = _set_se_translator(straight_to_debugger);
  141. </pre>
  142. </blockquote>
  143. This technique doesn't work if the SEH is raised from within a catch
  144. block (or a function called from within a catch block), but it still
  145. eliminates the vast majority of JIT-masking problems.
  146. <h3>How should I handle exceptions?</h3>
  147. <p>Often the best way to deal with exceptions is to not handle them at
  148. all. If you can let them pass through your code and allow destructors to
  149. handle cleanup, your code will be cleaner.</p>
  150. <h4>Avoid <code>catch(...)</code> when possible</h4>
  151. Unfortunately, operating systems other than Windows also wind non-C++
  152. "exceptions" (such as thread cancellation) into the C++ EH machinery, and
  153. there is sometimes no workaround corresponding to the
  154. <code>_set_se_translator</code> hack described above. The result is that
  155. <code>catch(...)</code> can have the effect of making some unexpected
  156. system notification at a point where recovery is impossible look just
  157. like a C++ exception thrown from a reasonable place, invalidating the
  158. usual safe assumptions that destructors and catch blocks have taken valid
  159. steps to ensure program invariants during unwinding. I reluctantly
  160. concede this point to Hillel Y. Sims, who beat it into me (&lt;wink&gt;):
  161. until all OSes are "fixed", if every exception were derived from
  162. <code>std::exception</code> and everyone substituted
  163. <code>catch(std::exception&amp;)</code> for <code>catch(...)</code>, the
  164. world would be a better place.
  165. <hr>
  166. <p>&copy; Copyright David Abrahams 2001-2003. Permission to copy,
  167. use, modify, sell and distribute this document is granted provided
  168. this copyright notice appears in all copies. This document is
  169. provided "as is" without express or implied warranty, and with no
  170. claim as to its suitability for any purpose.</p>
  171. <p>Revised
  172. <!--webbot bot="Timestamp" s-type="EDITED" s-format="%d %B, %Y" startspan -->
  173. 22 March, 2003<!--webbot bot="Timestamp" endspan i-checksum="34359" -->
  174. </p>
  175. </body>
  176. </html>
粤ICP备19079148号