mirror of
https://github.com/autc04/Retro68.git
synced 2024-11-28 05:51:04 +00:00
544 lines
17 KiB
XML
544 lines
17 KiB
XML
<section xmlns="http://docbook.org/ns/docbook" version="5.0"
|
|
xml:id="manual.intro.using.exceptions" xreflabel="Using Exceptions">
|
|
<?dbhtml filename="using_exceptions.html"?>
|
|
|
|
<info><title>Exceptions</title>
|
|
<keywordset>
|
|
<keyword>C++</keyword>
|
|
<keyword>exception</keyword>
|
|
<keyword>error</keyword>
|
|
<keyword>exception neutrality</keyword>
|
|
<keyword>exception safety</keyword>
|
|
<keyword>exception propagation</keyword>
|
|
<keyword>-fno-exceptions</keyword>
|
|
</keywordset>
|
|
</info>
|
|
|
|
<para>
|
|
The C++ language provides language support for stack unwinding
|
|
with <literal>try</literal> and <literal>catch</literal> blocks and
|
|
the <literal>throw</literal> keyword.
|
|
</para>
|
|
|
|
<para>
|
|
These are very powerful constructs, and require some thought when
|
|
applied to the standard library in order to yield components that work
|
|
efficiently while cleaning up resources when unexpectedly killed via
|
|
exceptional circumstances.
|
|
</para>
|
|
|
|
<para>
|
|
Two general topics of discussion follow:
|
|
exception neutrality and exception safety.
|
|
</para>
|
|
|
|
|
|
<section xml:id="intro.using.exception.safety" xreflabel="Exception Safety"><info><title>Exception Safety</title></info>
|
|
|
|
|
|
<para>
|
|
What is exception-safe code?
|
|
</para>
|
|
|
|
<para>
|
|
Will define this as reasonable and well-defined behavior by classes
|
|
and functions from the standard library when used by user-defined
|
|
classes and functions that are themselves exception safe.
|
|
</para>
|
|
|
|
<para>
|
|
Please note that using exceptions in combination with templates
|
|
imposes an additional requirement for exception
|
|
safety. Instantiating types are required to have destructors that
|
|
do no throw.
|
|
</para>
|
|
|
|
<para>
|
|
Using the layered approach from Abrahams, can classify library
|
|
components as providing set levels of safety. These will be called
|
|
exception guarantees, and can be divided into three categories.
|
|
</para>
|
|
|
|
<itemizedlist>
|
|
|
|
<listitem>
|
|
<para>
|
|
One. Don't throw.
|
|
</para>
|
|
<para>
|
|
As specified in 23.2.1 general container requirements. Applicable
|
|
to container and string classes.
|
|
</para>
|
|
<para>
|
|
Member
|
|
functions <function>erase</function>, <function>pop_back</function>, <function>pop_front</function>, <function>swap</function>, <function>clear</function>. And <type>iterator</type>
|
|
copy constructor and assignment operator.
|
|
</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>
|
|
Two. Don't leak resources when exceptions are thrown. This is
|
|
also referred to as the <quote>basic</quote> exception safety guarantee.
|
|
</para>
|
|
|
|
<para>
|
|
This applicable throughout the standard library.
|
|
</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>
|
|
Three. Commit-or-rollback semantics. This is
|
|
referred to as <quote>strong</quote> exception safety guarantee.
|
|
</para>
|
|
|
|
<para>
|
|
As specified in 23.2.1 general container requirements. Applicable
|
|
to container and string classes.
|
|
</para>
|
|
<para>
|
|
Member functions <function>insert</function> of a single
|
|
element, <function>push_back</function>, <function>push_front</function>,
|
|
and <function>rehash</function>.
|
|
</para>
|
|
|
|
</listitem>
|
|
</itemizedlist>
|
|
|
|
</section>
|
|
|
|
|
|
<section xml:id="intro.using.exception.propagating" xreflabel="Exceptions Neutrality"><info><title>Exception Neutrality</title></info>
|
|
|
|
<para>
|
|
Simply put, once thrown an exception object should continue in
|
|
flight unless handled explicitly. In practice, this means
|
|
propagating exceptions should not be swallowed in
|
|
gratuitous <literal>catch(...)</literal> blocks. Instead,
|
|
matching <literal>try</literal> and <literal>catch</literal>
|
|
blocks should have specific catch handlers and allow un-handed
|
|
exception objects to propagate. If a
|
|
terminating <literal>catch(...)</literal> blocks exist then it
|
|
should end with a <literal>throw</literal> to re-throw the current
|
|
exception.
|
|
</para>
|
|
|
|
<para>
|
|
Why do this?
|
|
</para>
|
|
|
|
<para>
|
|
By allowing exception objects to propagate, a more flexible
|
|
approach to error handling is made possible (although not
|
|
required.) Instead of dealing with an error immediately, one can
|
|
allow the exception to propagate up until sufficient context is
|
|
available and the choice of exiting or retrying can be made in an
|
|
informed manner.
|
|
</para>
|
|
|
|
<para>
|
|
Unfortunately, this tends to be more of a guideline than a strict
|
|
rule as applied to the standard library. As such, the following is
|
|
a list of known problem areas where exceptions are not propagated.
|
|
</para>
|
|
|
|
<itemizedlist>
|
|
<listitem>
|
|
<para>
|
|
Input/Output
|
|
</para>
|
|
<para>
|
|
The destructor <function>ios_base::Init::~Init()</function>
|
|
swallows all exceptions from <function>flush</function> called on
|
|
all open streams at termination.
|
|
</para>
|
|
|
|
<para>
|
|
All formatted input in <classname>basic_istream</classname> or
|
|
formatted output in <classname>basic_ostream</classname> can be
|
|
configured to swallow exceptions
|
|
when <function>exceptions</function> is set to
|
|
ignore <type>ios_base::badbit</type>.
|
|
</para>
|
|
|
|
<para>
|
|
Functions that have been registered
|
|
with <function>ios_base::register_callback</function> swallow all
|
|
exceptions when called as part of a callback event.
|
|
</para>
|
|
|
|
<para>
|
|
When closing the underlying
|
|
file, <function>basic_filebuf::close</function> will swallow
|
|
(non-cancellation) exceptions thrown and return <literal>NULL</literal>.
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
Thread
|
|
</para>
|
|
<para>
|
|
The constructors of <classname>thread</classname> that take a
|
|
callable function argument swallow all exceptions resulting from
|
|
executing the function argument.
|
|
</para>
|
|
</listitem>
|
|
</itemizedlist>
|
|
|
|
</section>
|
|
|
|
<section xml:id="intro.using.exception.no" xreflabel="-fno-exceptions"><info><title>Doing without</title></info>
|
|
|
|
<para>
|
|
C++ is a language that strives to be as efficient as is possible
|
|
in delivering features. As such, considerable care is used by both
|
|
language implementer and designers to make sure unused features
|
|
not impose hidden or unexpected costs. The GNU system tries to be
|
|
as flexible and as configurable as possible. So, it should come as
|
|
no surprise that GNU C++ provides an optional language extension,
|
|
spelled <literal>-fno-exceptions</literal>, as a way to excise the
|
|
implicitly generated magic necessary to
|
|
support <literal>try</literal> and <literal>catch</literal> blocks
|
|
and thrown objects. (Language support
|
|
for <literal>-fno-exceptions</literal> is documented in the GNU
|
|
GCC <link xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="http://gcc.gnu.org/onlinedocs/gcc/Code-Gen-Options.html#Code-Gen-Options">manual</link>.)
|
|
</para>
|
|
|
|
<para>Before detailing the library support
|
|
for <literal>-fno-exceptions</literal>, first a passing note on
|
|
the things lost when this flag is used: it will break exceptions
|
|
trying to pass through code compiled
|
|
with <literal>-fno-exceptions</literal> whether or not that code
|
|
has any <literal>try</literal> or <literal>catch</literal>
|
|
constructs. If you might have some code that throws, you shouldn't
|
|
use <literal>-fno-exceptions</literal>. If you have some code that
|
|
uses <literal>try</literal> or <literal>catch</literal>, you
|
|
shouldn't use <literal>-fno-exceptions</literal>.
|
|
</para>
|
|
|
|
<para>
|
|
And what it to be gained, tinkering in the back alleys with a
|
|
language like this? Exception handling overhead can be measured
|
|
in the size of the executable binary, and varies with the
|
|
capabilities of the underlying operating system and specific
|
|
configuration of the C++ compiler. On recent hardware with GNU
|
|
system software of the same age, the combined code and data size
|
|
overhead for enabling exception handling is around 7%. Of course,
|
|
if code size is of singular concern than using the appropriate
|
|
optimizer setting with exception handling enabled
|
|
(ie, <literal>-Os -fexceptions</literal>) may save up to twice
|
|
that, and preserve error checking.
|
|
</para>
|
|
|
|
<para>
|
|
So. Hell bent, we race down the slippery track, knowing the brakes
|
|
are a little soft and that the right front wheel has a tendency to
|
|
wobble at speed. Go on: detail the standard library support
|
|
for <literal>-fno-exceptions</literal>.
|
|
</para>
|
|
|
|
<para>
|
|
In sum, valid C++ code with exception handling is transformed into
|
|
a dialect without exception handling. In detailed steps: all use
|
|
of the C++
|
|
keywords <literal>try</literal>, <literal>catch</literal>,
|
|
and <literal>throw</literal> in the standard library have been
|
|
permanently replaced with the pre-processor controlled equivalents
|
|
spelled <literal>__try</literal>, <literal>__catch</literal>,
|
|
and <literal>__throw_exception_again</literal>. They are defined
|
|
as follows.
|
|
</para>
|
|
|
|
<programlisting>
|
|
#if __cpp_exceptions
|
|
# define __try try
|
|
# define __catch(X) catch(X)
|
|
# define __throw_exception_again throw
|
|
#else
|
|
# define __try if (true)
|
|
# define __catch(X) if (false)
|
|
# define __throw_exception_again
|
|
#endif
|
|
</programlisting>
|
|
|
|
<para>
|
|
In addition, for every object derived from
|
|
class <classname>exception</classname>, there exists a corresponding
|
|
function with C language linkage. An example:
|
|
</para>
|
|
|
|
<programlisting>
|
|
#if __cpp_exceptions
|
|
void __throw_bad_exception(void)
|
|
{ throw bad_exception(); }
|
|
#else
|
|
void __throw_bad_exception(void)
|
|
{ abort(); }
|
|
#endif
|
|
</programlisting>
|
|
|
|
<para>
|
|
The last language feature needing to be transformed
|
|
by <literal>-fno-exceptions</literal> is treatment of exception
|
|
specifications on member functions. Fortunately, the compiler deals
|
|
with this by ignoring exception specifications and so no alternate
|
|
source markup is needed.
|
|
</para>
|
|
|
|
<para>
|
|
By using this combination of language re-specification by the
|
|
compiler, and the pre-processor tricks and the functional
|
|
indirection layer for thrown exception objects by the library,
|
|
libstdc++ files can be compiled
|
|
with <literal>-fno-exceptions</literal>.
|
|
</para>
|
|
|
|
<para>
|
|
User code that uses C++ keywords
|
|
like <literal>throw</literal>, <literal>try</literal>,
|
|
and <literal>catch</literal> will produce errors even if the user
|
|
code has included libstdc++ headers and is using constructs
|
|
like <classname>basic_iostream</classname>. Even though the standard
|
|
library has been transformed, user code may need modification. User
|
|
code that attempts or expects to do error checking on standard
|
|
library components compiled with exception handling disabled should
|
|
be evaluated and potentially made conditional.
|
|
</para>
|
|
|
|
<para>
|
|
Some issues remain with this approach (see bugzilla entry
|
|
25191). Code paths are not equivalent, in
|
|
particular <literal>catch</literal> blocks are not evaluated. Also
|
|
problematic are <literal>throw</literal> expressions expecting a
|
|
user-defined throw handler. Known problem areas in the standard
|
|
library include using an instance
|
|
of <classname>basic_istream</classname>
|
|
with <function>exceptions</function> set to specific
|
|
<type>ios_base::iostate</type> conditions, or
|
|
cascading <literal>catch</literal> blocks that dispatch error
|
|
handling or recovery efforts based on the type of exception object
|
|
thrown.
|
|
</para>
|
|
|
|
<para>
|
|
Oh, and by the way: none of this hackery is at all
|
|
special. (Although perhaps well-deserving of a raised eyebrow.)
|
|
Support continues to evolve and may change in the future. Similar
|
|
and even additional techniques are used in other C++ libraries and
|
|
compilers.
|
|
</para>
|
|
|
|
<para>
|
|
C++ hackers with a bent for language and control-flow purity have
|
|
been successfully consoled by grizzled C veterans lamenting the
|
|
substitution of the C language keyword
|
|
<literal>const</literal> with the uglified
|
|
doppelganger <literal>__const</literal>.
|
|
</para>
|
|
|
|
|
|
</section>
|
|
|
|
<section xml:id="intro.using.exception.compat"><info><title>Compatibility</title></info>
|
|
|
|
|
|
<section xml:id="using.exception.compat.c"><info><title>With <literal>C</literal></title></info>
|
|
|
|
<para>
|
|
C language code that is expecting to interoperate with C++ should be
|
|
compiled with <literal>-fexceptions</literal>. This will make
|
|
debugging a C language function called as part of C++-induced stack
|
|
unwinding possible.
|
|
</para>
|
|
|
|
<para>
|
|
In particular, unwinding into a frame with no exception handling
|
|
data will cause a runtime abort. If the unwinder runs out of unwind
|
|
info before it finds a handler, <function>std::terminate()</function>
|
|
is called.
|
|
</para>
|
|
|
|
<para>
|
|
Please note that most development environments should take care of
|
|
getting these details right. For GNU systems, all appropriate parts
|
|
of the GNU C library are already compiled
|
|
with <literal>-fexceptions</literal>.
|
|
</para>
|
|
|
|
</section>
|
|
|
|
<section xml:id="using.exception.compat.posix"><info><title>With <literal>POSIX</literal> thread cancellation</title></info>
|
|
|
|
|
|
<para>
|
|
GNU systems re-use some of the exception handling mechanisms to
|
|
track control flow for <literal>POSIX</literal> thread cancellation.
|
|
</para>
|
|
|
|
<para>
|
|
Cancellation points are functions defined by POSIX as worthy of
|
|
special treatment. The standard library may use some of these
|
|
functions to implement parts of the ISO C++ standard or depend on
|
|
them for extensions.
|
|
</para>
|
|
|
|
<para>
|
|
Of note:
|
|
</para>
|
|
|
|
<para>
|
|
<function>nanosleep</function>,
|
|
<function>read</function>, <function>write</function>, <function>open</function>, <function>close</function>,
|
|
and <function>wait</function>.
|
|
</para>
|
|
|
|
<para>
|
|
The parts of libstdc++ that use C library functions marked as
|
|
cancellation points should take pains to be exception neutral.
|
|
Failing this, <literal>catch</literal> blocks have been augmented to
|
|
show that the POSIX cancellation object is in flight.
|
|
</para>
|
|
|
|
<para>
|
|
This augmentation adds a <literal>catch</literal> block
|
|
for <classname>__cxxabiv1::__forced_unwind</classname>, which is the
|
|
object representing the POSIX cancellation object. Like so:
|
|
</para>
|
|
|
|
<programlisting>
|
|
catch(const __cxxabiv1::__forced_unwind&)
|
|
{
|
|
this->_M_setstate(ios_base::badbit);
|
|
throw;
|
|
}
|
|
catch(...)
|
|
{ this->_M_setstate(ios_base::badbit); }
|
|
</programlisting>
|
|
|
|
|
|
</section>
|
|
</section>
|
|
|
|
<bibliography xml:id="using.exceptions.biblio"><info><title>Bibliography</title></info>
|
|
|
|
|
|
<biblioentry>
|
|
<title>
|
|
<link xmlns:xlink="http://www.w3.org/1999/xlink"
|
|
xlink:href="http://www.opengroup.org/austin/">
|
|
System Interface Definitions, Issue 7 (IEEE Std. 1003.1-2008)
|
|
</link>
|
|
</title>
|
|
|
|
|
|
<pagenums>
|
|
2.9.5 Thread Cancellation
|
|
</pagenums>
|
|
<copyright>
|
|
<year>2008</year>
|
|
<holder>
|
|
The Open Group/The Institute of Electrical and Electronics
|
|
Engineers, Inc.
|
|
</holder>
|
|
</copyright>
|
|
</biblioentry>
|
|
|
|
<biblioentry>
|
|
<title>
|
|
<link xmlns:xlink="http://www.w3.org/1999/xlink"
|
|
xlink:href="http://www.boost.org/community/error_handling.html">
|
|
Error and Exception Handling
|
|
</link>
|
|
</title>
|
|
|
|
<author><personname><firstname>David</firstname><surname>Abrahams </surname></personname></author>
|
|
<publisher>
|
|
<publishername>
|
|
Boost
|
|
</publishername>
|
|
</publisher>
|
|
</biblioentry>
|
|
|
|
|
|
<biblioentry>
|
|
<title>
|
|
<link xmlns:xlink="http://www.w3.org/1999/xlink"
|
|
xlink:href="http://www.boost.org/community/exception_safety.html">
|
|
Exception-Safety in Generic Components
|
|
</link>
|
|
</title>
|
|
|
|
<author><personname><firstname>David</firstname><surname>Abrahams</surname></personname></author>
|
|
<publisher>
|
|
<publishername>
|
|
Boost
|
|
</publishername>
|
|
</publisher>
|
|
</biblioentry>
|
|
|
|
<biblioentry>
|
|
<title>
|
|
<link xmlns:xlink="http://www.w3.org/1999/xlink"
|
|
xlink:href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/1997/N1077.pdf">
|
|
Standard Library Exception Policy
|
|
</link>
|
|
</title>
|
|
|
|
<author><personname><firstname>Matt</firstname><surname>Austern</surname></personname></author>
|
|
<publisher>
|
|
<publishername>
|
|
WG21 N1077
|
|
</publishername>
|
|
</publisher>
|
|
</biblioentry>
|
|
|
|
<biblioentry>
|
|
<title>
|
|
<link xmlns:xlink="http://www.w3.org/1999/xlink"
|
|
xlink:href="http://gcc.gnu.org/ml/gcc-patches/2001-03/msg00661.html">
|
|
ia64 c++ abi exception handling
|
|
</link>
|
|
</title>
|
|
|
|
<author><personname><firstname>Richard</firstname><surname>Henderson</surname></personname></author>
|
|
<publisher>
|
|
<publishername>
|
|
GNU
|
|
</publishername>
|
|
</publisher>
|
|
</biblioentry>
|
|
|
|
<biblioentry>
|
|
<title>
|
|
<link xmlns:xlink="http://www.w3.org/1999/xlink"
|
|
xlink:href="http://www.stroustrup.com/3rd_safe.pdf">
|
|
Appendix E: Standard-Library Exception Safety
|
|
</link>
|
|
</title>
|
|
<author><personname><firstname>Bjarne</firstname><surname>Stroustrup</surname></personname></author>
|
|
</biblioentry>
|
|
|
|
<biblioentry>
|
|
<citetitle>
|
|
Exceptional C++
|
|
</citetitle>
|
|
<pagenums>
|
|
Exception-Safety Issues and Techniques
|
|
</pagenums>
|
|
<author><personname><firstname>Herb</firstname><surname>Sutter</surname></personname></author>
|
|
</biblioentry>
|
|
|
|
<biblioentry>
|
|
<title>
|
|
<link xmlns:xlink="http://www.w3.org/1999/xlink"
|
|
xlink:href="http://gcc.gnu.org/PR25191">
|
|
GCC Bug 25191: exception_defines.h #defines try/catch
|
|
</link>
|
|
</title>
|
|
</biblioentry>
|
|
|
|
</bibliography>
|
|
|
|
</section>
|