mirror of
https://github.com/boostorg/more.git
synced 2024-12-27 23:40:13 +08:00
updated guidelines
[SVN r18047]
This commit is contained in:
parent
7523019953
commit
70fc63b56b
@ -1,15 +1,22 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 3.2//EN">
|
||||
<meta name="generator" content="HTML Tidy, see www.w3.org">
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=windows-1252">
|
||||
|
||||
<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:
|
||||
writing robust generic components:</p>
|
||||
|
||||
<blockquote>
|
||||
<a href="generic_exception_safety.html">D. Abrahams: ``Exception Safety
|
||||
@ -24,7 +31,7 @@
|
||||
<h3>When should I use exceptions?</h3>
|
||||
|
||||
<p>The simple answer is: ``whenever the semantic and performance
|
||||
characteristics of exceptions are appropriate.''
|
||||
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
|
||||
@ -32,7 +39,7 @@
|
||||
``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.
|
||||
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
|
||||
@ -40,9 +47,70 @@
|
||||
``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 would have a significant performance impact.
|
||||
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.</p>
|
||||
|
||||
<h3>How should I design my exception classes?</h3>
|
||||
|
||||
<ol>
|
||||
<li><b>Inherit 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>
|
||||
|
||||
<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 to termination during stack unwinding. Similarly,
|
||||
it's a bad idea to use a base or member whose ordinary constructor
|
||||
might throw, because, though not fatal, you will report a different
|
||||
exception than intended when that happens in a
|
||||
<i>throw-expression</i> 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 messages. Now if only we could get
|
||||
standardized <code>what()</code> strings for exceptions thrown by the
|
||||
standard library...</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>
|
||||
|
||||
@ -50,26 +118,27 @@
|
||||
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.
|
||||
something like it.</p>
|
||||
|
||||
<p>Sometimes it is neccessary 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>Sometimes it is neccessary 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.
|
||||
Fortunately, there is a simple but little-known workaround, which is to use
|
||||
the following incantation:
|
||||
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>
|
||||
@ -81,12 +150,43 @@ 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. I reluctantly
|
||||
concede this point to Hillel Y. Sims, who beat it into me (<wink>):
|
||||
until all OSes are "fixed", if every exception were derived from
|
||||
<code>std::exception</code> and everyone substituted
|
||||
<code>catch(std::exception&)</code> for <code>catch(...)</code>, the
|
||||
world would be a better place.
|
||||
<hr>
|
||||
|
||||
<p>© Copyright David Abrahams 2001. Permission to copy, use, modify,
|
||||
sell and distribute this document is granted provided this copyright notice
|
||||
appears in all copies. This document is provided "as is" without express or
|
||||
implied warranty, and with no claim as to its suitability for any purpose.
|
||||
sell and distribute this document is granted provided this copyright
|
||||
notice appears in all copies. This document is provided "as is" without
|
||||
express or implied warranty, and with no claim as to its suitability for
|
||||
any purpose.</p>
|
||||
|
||||
<p>Revised
|
||||
<!--webbot bot="Timestamp" s-type="EDITED" s-format="%d %B, %Y" startspan -->19 August, 2001<!--webbot bot="Timestamp" endspan i-checksum="34359" -->
|
||||
<!--webbot bot="Timestamp" s-type="EDITED" s-format="%d %B, %Y" startspan -->
|
||||
22 March, 2003<!--webbot bot="Timestamp" endspan i-checksum="34359" -->
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user