⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 chap01.htm

📁 This is the second part of that lab manual to teach you how to make real-time programme and how to d
💻 HTM
📖 第 1 页 / 共 5 页
字号:

<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#0000ff>throw</font> myerror(&#8220;something bad happened&#8221;);</PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia"><B>myerror</B> is an ordinary class,
which takes a <B>char*</B> as its argument. You can use any type when you throw
(including built-in types), but often you&#8217;ll use special types created
just for throwing exceptions.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The keyword <B>throw</B> causes a number
of relatively magical things to happen. First it creates an object that
isn&#8217;t there under normal program execution, and of course the constructor
is called for that object. Then the object is, in effect, &#8220;returned&#8221;
from the function, even though that object type isn&#8217;t normally what the
function is designed to return. A simplistic way to think about exception
handling is as an alternate return mechanism, although you get into trouble if
you take the analogy too far &#8211; you can also exit from ordinary scopes by
throwing an exception. But a value is returned, and the function or scope
exits.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Any similarity to function returns ends
there because <I>where</I> you return to is someplace completely different than
for a normal function call. (You end up in an appropriate exception handler that
may be miles away from where the exception was thrown.) In addition, only
objects that were successfully created at the time of the exception are
destroyed (unlike a normal function return that assumes all the objects in the
scope must be destroyed). Of course, the exception object itself is also
properly cleaned up at the appropriate point.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">In addition, you can throw as many
different types of objects as you want. Typically, you&#8217;ll throw a
different type for each different type of error. The idea is to store the
information in the object and the <I>type</I> of object, so someone in the
bigger context can figure out what to do with your
exception.</FONT><A NAME="_Toc305593298"></A><A NAME="_Toc305628770"></A><A NAME="_Toc312374113"></A><A NAME="_Toc519041882"></A><BR></P></DIV>
<A NAME="Heading21"></A><FONT FACE = "Verdana, Tahoma, Arial, Helvetica, Sans"><H2 ALIGN="LEFT">
Catching an exception</H2></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">If a function throws an exception, it
must assume that exception is caught and dealt with. As mentioned before, one of
the advantages of C++ exception handling is that it allows you to concentrate on
the problem you&#8217;re actually trying to solve in one place, and then deal
with the errors from that code in another
place.</FONT><A NAME="_Toc312374114"></A><A NAME="_Toc519041883"></A><BR></P></DIV>
<A NAME="Heading22"></A><FONT FACE = "Verdana, Tahoma, Arial, Helvetica, Sans"><H3 ALIGN="LEFT">
The try block</H3></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">If you&#8217;re inside a function and you
throw an exception (or a called function throws an exception), that function
will exit in the process of throwing. If you don&#8217;t want a <B>throw </B>to
leave a function, you can set up a special block within the function where you
try to solve your actual programming problem (and potentially generate
exceptions). This is called the <I>try</I> <I>block<A NAME="Index28"></A></I>
because you try your various function calls there. The try block is an ordinary
scope, preceded by the keyword <B>try</B>:</FONT><BR></P></DIV>

<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#0000ff>try</font> {
  <font color=#009900>// Code that may generate exceptions</font>
}</PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">If you were carefully checking for errors
without using exception handling, you&#8217;d have to surround every function
call with setup and test code, even if you call the same function several times.
With exception handling, you put everything in a try block without error
checking. This means your code is a lot easier to write and easier to read
because the goal of the code is not confused with the error
checking.</FONT><A NAME="_Toc312374115"></A><A NAME="_Toc519041884"></A><BR></P></DIV>
<A NAME="Heading23"></A><FONT FACE = "Verdana, Tahoma, Arial, Helvetica, Sans"><H3 ALIGN="LEFT">
Exception handlers</H3></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Of course, the thrown exception must end
up someplace. This is the <I>exception
handler<A NAME="Index29"></A><A NAME="Index30"></A></I>, and there&#8217;s one
for every exception type you want to catch. Exception handlers immediately
follow the try block and are denoted by the keyword
<B>catch<A NAME="Index31"></A><A NAME="Index32"></A></B>:</FONT><BR></P></DIV>

<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#0000ff>try</font> {
<font color=#009900>// Code that may generate exceptions</font>
} <font color=#0000ff>catch</font>(type1 id1) {
  <font color=#009900>// Handle exceptions of type1</font>
} <font color=#0000ff>catch</font>(type2 id2) {
  <font color=#009900>// Handle exceptions of type2</font>
}
<font color=#009900>// Etc...</font></PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Each catch clause (exception handler) is
like a little function that takes a single argument of one particular type. The
identifier (<B>id1</B>, <B>id2</B>, and so on) may be used inside the handler,
just like a function argument, although sometimes there is no identifier because
it&#8217;s not needed in the handler &#8211; the exception type gives you enough
information to deal with it.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The handlers must appear directly after
the try block. If an exception is thrown, the exception-handling mechanism goes
hunting for the first handler with an argument that matches the type of the
exception. Then it enters that catch clause, and the exception is considered
handled. (The search for handlers stops once the catch clause is finished.) Only
the matching catch clause executes; it&#8217;s not like a <B>switch</B>
statement where you need a <B>break</B> after each <B>case</B> to prevent the
remaining ones from executing.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Notice that, within the try block, a
number of different function calls might generate the same exception, but you
only need one handler.</FONT><BR></P></DIV>
<A NAME="Heading24"></A><FONT FACE = "Verdana, Tahoma, Arial, Helvetica, Sans"><H4 ALIGN="LEFT">
Termination vs.
resumption<BR><A NAME="Index33"></A><A NAME="Index34"></A><A NAME="Index35"></A></H4></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">There are two basic models in
exception-handling theory. In <I>termination</I> (which is what C++ supports)
you assume the error is so critical there&#8217;s no way to get back to where
the exception occurred. Whoever threw the exception decided there was no way to
salvage the situation, and they don&#8217;t <I>want</I> to come
back.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The alternative is called
<I>resumption</I>. It means the exception handler is expected to do something to
rectify the situation, and then the faulting function is retried, presuming
success the second time. If you want resumption, you still hope to continue
execution after the exception is handled, so your exception is more like a
function call &#8211; which is how you should set up situations in C++ where you
want resumption-like behavior (that is, don&#8217;t throw an exception; call a
function that fixes the problem). Alternatively, place your <B>try</B> block
inside a <B>while</B> loop that keeps reentering the <B>try</B> block until the
result is satisfactory.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Historically, programmers using operating
systems that supported resumptive exception handling eventually ended up using
termination-like code and skipping resumption. So although resumption sounds
attractive at first, it seems it isn&#8217;t quite so useful in practice. One
reason may be the distance that can occur between the exception and its handler;
it&#8217;s one thing to terminate to a handler that&#8217;s far away, but to
jump to that handler and then back again may be too conceptually difficult for
large systems where the exception can be generated from many
points.</FONT><A NAME="_Toc312374116"></A><A NAME="_Toc519041885"></A><BR></P></DIV>
<A NAME="Heading25"></A><FONT FACE = "Verdana, Tahoma, Arial, Helvetica, Sans"><H3 ALIGN="LEFT">
The exception specification<BR><A NAME="Index36"></A><A NAME="Index37"></A></H3></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">You&#8217;re not required to inform the
person using your function what exceptions you might throw. However, this is
considered very uncivilized because it means he cannot be sure what code to
write to catch all potential exceptions. Of course, if he has your source code,
he can hunt through and look for <B>throw</B> statements, but very often a
library doesn&#8217;t come with sources. C++ provides a syntax to allow you to
politely tell the user what exceptions this function throws, so the user may
handle them. This is the <I>exception specification</I> and it&#8217;s part of
the function declaration, appearing after the argument list.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The exception specification reuses the
keyword <B>throw</B>, followed by a parenthesized list of all the potential
exception types. So your function declaration may look like</FONT><BR></P></DIV>

<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#0000ff>void</font> f() <font color=#0000ff>throw</font>(toobig, toosmall, divzero);</PRE></FONT></BLOCKQUOTE><DIV ALIGN="LEFT"><P><FONT FACE="Georgia">With
exceptions, the traditional function declaration</FONT><BR></P></DIV>

<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#0000ff>void</font> f();</PRE></FONT></BLOCKQUOTE><DIV ALIGN="LEFT"><P><FONT FACE="Georgia">means that any type
of exception may be thrown from the function. If you say</FONT><BR></P></DIV>

<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#0000ff>void</font> f() <font color=#0000ff>throw</font>();</PRE></FONT></BLOCKQUOTE><DIV ALIGN="LEFT"><P><FONT FACE="Georgia">it means that
no exceptions are thrown from a function.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">For good coding policy, good
documentation, and ease-of-use for the function caller, you should always use an
exception specification when you write a function that throws
exceptions.</FONT><BR></P></DIV>
<A NAME="Heading26"></A><FONT FACE = "Verdana, Tahoma, Arial, Helvetica, Sans"><H4 ALIGN="LEFT">
unexpected(&#160;)</H4></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">If your exception specification claims
you&#8217;re going to throw a certain set of exceptions and then you throw
something that isn&#8217;t in that set, what&#8217;s the penalty? The special
function <B>unexpected(&#160;)</B> is called when you throw something other than
what appears in the exception specification.</FONT><BR></P></DIV>
<A NAME="Heading27"></A><FONT FACE = "Verdana, Tahoma, Arial, Helvetica, Sans"><H4 ALIGN="LEFT">
set_unexpected(&#160;)</H4></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia"><B>unexpected(&#160;)<A NAME="Index38"></A><A NAME="Index39"></A></B>
is implemented with a pointer to a function, so you can change its behavior. You
do so with a function called
<B>set_unexpected(&#160;)<A NAME="Index40"></A><A NAME="Index41"></A></B> which,
like <B>set_new_handler(&#160;)</B>, takes the address of a function with no
arguments and <B>void</B> return value. Also, it returns the previous value of
the <B>unexpected(&#160;)</B> pointer so you can save it and restore it later.
To use <B>set_unexpected(&#160;)</B>, you must include the header file
<B>&lt;exception&gt;</B>. Here&#8217;s an example that shows a simple use of all
the features discussed so far in the chapter:</FONT><BR></P></DIV>

<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#009900>//: C01:Except.cpp</font>
<font color=#009900>// Basic exceptions</font>
<font color=#009900>// Exception specifications &amp; unexpected()</font>
<font color=#009900>//{L} ../TestSuite/Test</font>
#include &lt;exception&gt;
#include &lt;iostream&gt;
#include &lt;cstdlib&gt;
#include &lt;cstring&gt;
<font color=#0000ff>using</font> <font color=#0000ff>namespace</font> std;

<font color=#0000ff>class</font> Up {};
<font color=#0000ff>class</font> Fit {};
<font color=#0000ff>void</font> g();

<font color=#0000ff>void</font> f(<font color=#0000ff>int</font> i) <font color=#0000ff>throw</font> (Up, Fit) {
  <font color=#0000ff>switch</font>(i) {
    <font color=#0000ff>case</font> 1: <font color=#0000ff>throw</font> Up();
    <font color=#0000ff>case</font> 2: <font color=#0000ff>throw</font> Fit();
  }
  g();
}

<font color=#009900>// void g() {} // Version 1</font>
<font color=#0000ff>void</font> g() { <font color=#0000ff>throw</font> 47; } <font color=#009900>// Version 2</font>
<font color=#009900>// (Can throw built-in types)</font>

<font color=#0000ff>void</font> my_unexpected() {
  cout &lt;&lt; <font color=#004488>"unexpected exception thrown"</font> &lt;&lt; endl;
  exit(0);
}

<font color=#0000ff>int</font> main() {
  set_unexpected(my_unexpected);
  <font color=#009900>// (ignores return value)</font>
  <font color=#0000ff>for</font>(<font color=#0000ff>int</font> i = 1; i &lt;=3; i++)
    <font color=#0000ff>try</font> {
      f(i);
    } <font color=#0000ff>catch</font>(Up) {
      cout &lt;&lt; <font color=#004488>"Up caught"</font> &lt;&lt; endl;
    } <font color=#0000ff>catch</font>(Fit) {
      cout &lt;&lt; <font color=#004488>"Fit caught"</font> &lt;&lt; endl;
    }
} <font color=#009900>///:~</font></PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The classes <B>Up</B> and <B>Fit</B> are
created solely to throw as exceptions. Often exception classes will be this
small, but sometimes they contain additional information so that the handlers
can query them.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia"><B>f(&#160;)</B> is a function that
promises in its exception specification to throw only exceptions of type
<B>Up</B> and <B>Fit</B>, and from looking at the function definition this seems
plausible. Version one of <B>g(&#160;)</B>, called by <B>f(&#160;)</B>,
doesn&#8217;t throw any exceptions so this is true. But then someone changes

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -