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

📄 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 页
字号:
<font color=#0000ff>using</font> <font color=#0000ff>namespace</font> std;

<font color=#0000ff>int</font> main() <font color=#0000ff>try</font> {
    <font color=#0000ff>throw</font> <font color=#004488>"main"</font>;
} <font color=#0000ff>catch</font>(<font color=#0000ff>const</font> <font color=#0000ff>char</font>* msg) {
  cout &lt;&lt; msg &lt;&lt; endl;
} <font color=#009900>///:~</font></PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><A NAME="_Toc519041891"></A><BR></P></DIV>
<A NAME="Heading35"></A><FONT FACE = "Verdana, Tahoma, Arial, Helvetica, Sans"><H2 ALIGN="LEFT">
Cleaning up<BR><A NAME="Index60"></A><A NAME="Index61"></A></H2></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Part of the magic of exception handling
is that you can pop from normal program flow into the appropriate exception
handler. This wouldn&#8217;t be very useful, however, if things weren&#8217;t
cleaned up properly as the exception was thrown. C++ exception handling
guarantees that as you leave a scope, all objects in that scope <I>whose
constructors have been completed</I> will have destructors
called.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Here&#8217;s an example that demonstrates
that constructors<A NAME="Index62"></A><A NAME="Index63"></A> that aren&#8217;t
completed don&#8217;t have the associated destructors called. It also shows what
happens when an exception is thrown in the middle of the creation of an array of
objects, and an <B>unexpected(&#160;)</B> function that prints a message and
exits the program:</FONT><BR></P></DIV>

<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#009900>//: C01:Cleanup.cpp</font>
<font color=#009900>// Exceptions clean up objects</font>
<font color=#009900>//{L} ../TestSuite/Test</font>
<font color=#009900>//{-g++3} g++3.0.1 dumps core</font>
#include &lt;fstream&gt;
#include &lt;exception&gt;
#include &lt;cstring&gt;
<font color=#0000ff>using</font> <font color=#0000ff>namespace</font> std;
ofstream out(<font color=#004488>"cleanup.out"</font>);

<font color=#0000ff>class</font> Noisy {
  <font color=#0000ff>static</font> <font color=#0000ff>int</font> i;
  <font color=#0000ff>int</font> objnum;
  <font color=#0000ff>enum</font> {sz = 40};
  <font color=#0000ff>char</font> name[sz];
<font color=#0000ff>public</font>:
  Noisy(<font color=#0000ff>const</font> <font color=#0000ff>char</font>* nm=<font color=#004488>"array elem"</font>) <font color=#0000ff>throw</font>(<font color=#0000ff>int</font>){
    objnum = i++;
    memset(name, 0, sz);
    strncpy(name, nm, sz - 1);
    out &lt;&lt; <font color=#004488>"constructing Noisy "</font> &lt;&lt; objnum
      &lt;&lt; <font color=#004488>" name ["</font> &lt;&lt; name &lt;&lt; <font color=#004488>"]"</font> &lt;&lt; endl;
    <font color=#0000ff>if</font>(objnum == 5) <font color=#0000ff>throw</font> <font color=#0000ff>int</font>(5);
    <font color=#009900>// Not in exception specification:</font>
    <font color=#0000ff>if</font>(*nm == 'z') <font color=#0000ff>throw</font> <font color=#0000ff>char</font>('z');
  }
  ~Noisy() {
    out &lt;&lt; <font color=#004488>"destructing Noisy "</font> &lt;&lt; objnum
      &lt;&lt; <font color=#004488>" name ["</font> &lt;&lt; name &lt;&lt; <font color=#004488>"]"</font> &lt;&lt; endl;
  }
  <font color=#0000ff>void</font>* <font color=#0000ff>operator</font> <font color=#0000ff>new</font>[](size_t sz) {
    out &lt;&lt; <font color=#004488>"Noisy::new[]"</font> &lt;&lt; endl;
    <font color=#0000ff>return</font> ::<font color=#0000ff>new</font> <font color=#0000ff>char</font>[sz];
  }
  <font color=#0000ff>void</font> <font color=#0000ff>operator</font> <font color=#0000ff>delete</font>[](<font color=#0000ff>void</font>* p) {
    out &lt;&lt; <font color=#004488>"Noisy::delete[]"</font> &lt;&lt; endl;
    ::<font color=#0000ff>delete</font> []p;
  }
};

<font color=#0000ff>int</font> Noisy::i = 0;

<font color=#0000ff>void</font> unexpected_rethrow() {
  out &lt;&lt; <font color=#004488>"inside unexpected_rethrow()"</font> &lt;&lt; endl;
  exit(0); <font color=#009900>// Rethrow same exception</font>
}

<font color=#0000ff>int</font> main() {
  set_unexpected(unexpected_rethrow);
  <font color=#0000ff>try</font> {
    Noisy n1(<font color=#004488>"before array"</font>);
    <font color=#009900>// Throws exception:</font>
    Noisy* array = <font color=#0000ff>new</font> Noisy[7];
    Noisy n2(<font color=#004488>"after array"</font>);
  } <font color=#0000ff>catch</font>(<font color=#0000ff>int</font> i) {
    out &lt;&lt; <font color=#004488>"caught "</font> &lt;&lt; i &lt;&lt; endl;
  }
  out &lt;&lt; <font color=#004488>"testing unexpected:"</font> &lt;&lt; endl;
  <font color=#0000ff>try</font> {
    Noisy n3(<font color=#004488>"before unexpected"</font>);
    Noisy n4(<font color=#004488>"z"</font>);
    Noisy n5(<font color=#004488>"after unexpected"</font>);
  } <font color=#0000ff>catch</font>(<font color=#0000ff>char</font> c) {
    out &lt;&lt; <font color=#004488>"caught "</font> &lt;&lt; c &lt;&lt; endl;
  }
} <font color=#009900>///:~</font></PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The class <B>Noisy</B> keeps track of
objects so you can trace program progress. It keeps a count of the number of
objects created with a <B>static</B> data member <B>i</B>, and the number of the
particular object with <B>objnum</B>, and a character buffer called <B>name</B>
to hold an identifier. This buffer is first set to zeroes. Then the constructor
argument is copied in. (Note that a default argument string is used to indicate
array elements, so this constructor also acts as a default constructor.) Because
the Standard C library function <B>strncpy(&#160;)
<A NAME="Index64"></A><A NAME="Index65"></A></B>stops copying after a null
terminator <I>or</I> the number of characters specified by its third argument,
the number of characters copied in is one minus the size of the buffer, so the
last character is always zero, and a print statement will never run off the end
of the buffer.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">There are two cases where a <B>throw</B>
can occur in the constructor. The first case happens if this is the fifth object
created (not a real exception condition, but demonstrates an exception thrown
during array construction). The type thrown is <B>int</B>, which is the type
promised in the exception specification. The second case, also contrived,
happens if the first character of the argument string is <B>&#8216;z&#8217;</B>,
in which case a <B>char</B> is thrown. Because <B>char</B> is not listed in the
exception specification, this will cause a call to
<B>unexpected(&#160;)</B>.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The array versions of <B>new</B> and
<B>delete</B> are overloaded
<A NAME="Index66"></A><A NAME="Index67"></A><A NAME="Index68"></A>for the class,
so you can see when they&#8217;re called.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The function
<B>unexpected_rethrow(&#160;)</B> prints a message and then exits the program.
It is installed as the <B>unexpected(&#160;)</B> function in the first line of
<B>main(&#160;)</B>. Then some objects of type <B>Noisy</B> are created in a
<B>try</B> block, but the array causes an exception to be thrown, so the object
<B>n2</B> is never created. You can see the results in the output of the
program:</FONT><BR></P></DIV>

<BLOCKQUOTE><FONT SIZE = "+1"><PRE>constructing Noisy 0 name [before array]
Noisy::<font color=#0000ff>new</font>[]
constructing Noisy 1 name [array elem]
constructing Noisy 2 name [array elem]
constructing Noisy 3 name [array elem]
constructing Noisy 4 name [array elem]
constructing Noisy 5 name [array elem]
destructing Noisy 4 name [array elem]
destructing Noisy 3 name [array elem]
destructing Noisy 2 name [array elem]
destructing Noisy 1 name [array elem]
Noisy::<font color=#0000ff>delete</font>[]
destructing Noisy 0 name [before array]
caught 5
testing unexpected:
constructing Noisy 6 name [before unexpected]
constructing Noisy 7 name [z]
inside unexpected_rethrow()
destructing Noisy 6 name [before unexpected]
caught z</PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Four array elements are successfully
created, but in the middle of the constructor for the fifth one, an exception is
thrown. Because the fifth constructor never completes, only the destructors for
objects 1&#8211;4 are called. </FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The storage for the array is allocated
separately with a single call to the global <B>new</B>. Notice that even though
<B>delete</B> is never explicitly called anywhere in the program, the
exception-handling system knows it must call <B>delete</B> to properly release
the storage. This behavior happens only with &#8220;normal&#8221; versions of
<B>operator new</B>. If you use the placement
syntax<A NAME="Index69"></A><A NAME="Index70"></A> described in Chapter XX, the
exception-handling mechanism will not call <B>delete</B> for that object because
then it might release memory that was not allocated on the
heap.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Finally, object <B>n1</B> is destroyed,
but not object <B>n2</B> because it was never created.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">In the section testing
<B>unexpected_rethrow(&#160;)</B>, the <B>n3</B> object is created, and the
constructor of <B>n4</B> is begun. But before it can complete, an exception is
thrown. This exception is of type <B>char</B>, which violates the exception
specification, so the <B>unexpected(&#160;)</B> function is called (which is
<B>unexpected_rethrow(&#160;)</B>, in this case). This rethrows the same
exception, which is expected this time, because
<B>unexpected_rethrow(&#160;)</B> can throw any type of exception. The search
begins right after the constructor for <B>n4</B>, and the <B>char</B> exception
handler catches it (after destroying <B>n3</B>, the only successfully created
object). Thus, the effect of <B>unexpected_rethrow(&#160;)</B> is to take any
unexpected exception and make it expected; used this way it provides a filter to
allow you to track the appearance of unexpected
exceptions<A NAME="Index71"></A><A NAME="Index72"></A> and pass them
through.</FONT><A NAME="_Toc305593300"></A><A NAME="_Toc305628772"></A><A NAME="_Toc312374122"></A><A NAME="_Toc519041892"></A><BR></P></DIV>
<A NAME="Heading36"></A><FONT FACE = "Verdana, Tahoma, Arial, Helvetica, Sans"><H2 ALIGN="LEFT">
Constructors<BR><A NAME="Index73"></A><A NAME="Index74"></A></H2></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">When writing code with exceptions,
it&#8217;s particularly important that you always be asking, &#8220;If an
exception occurs, will this be properly cleaned up?&#8221; Most of the time
you&#8217;re fairly safe, but in constructors there&#8217;s a problem: If an
exception is thrown before a constructor is completed, the associated destructor
will not be called for that object. This means you must be especially diligent
while writing your constructor.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The general difficulty is allocating
resources in constructors. If an exception occurs in the constructor, the
destructor doesn&#8217;t get a chance to deallocate the resource. This problem
occurs most often with &#8220;naked&#8221;
pointers<A NAME="Index75"></A><A NAME="Index76"></A>. For
example,</FONT><BR></P></DIV>

<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#009900>//: C01:Rawp.cpp</font>
<font color=#009900>// Naked pointers</font>
<font color=#009900>//{L} ../TestSuite/Test</font>
#include &lt;fstream&gt;
#include &lt;cstdlib&gt;
<font color=#0000ff>using</font> <font color=#0000ff>namespace</font> std;
ofstream out(<font color=#004488>"rawp.out"</font>);

<font color=#0000ff>class</font> Cat {
<font color=#0000ff>public</font>:
  Cat() { out &lt;&lt; <font color=#004488>"Cat()"</font> &lt;&lt; endl; }
  ~Cat() { out &lt;&lt; <font color=#004488>"~Cat()"</font> &lt;&lt; endl; }
};

<font color=#0000ff>class</font> Dog {
<font color=#0000ff>public</font>:
  <font color=#0000ff>void</font>* <font color=#0000ff>operator</font> <font color=#0000ff>new</font>(size_t sz) {
    out &lt;&lt; <font color=#004488>"allocating a Dog"</font> &lt;&lt; endl;
    <font color=#0000ff>throw</font> <font color=#0000ff>int</font>(47);
  }
  <font color=#0000ff>void</font> <font color=#0000ff>operator</font> <font color=#0000ff>delete</font>(<font color=#0000ff>void</font>* p) {
    out &lt;&lt; <font color=#004488>"deallocating a Dog"</font> &lt;&lt; endl;
    ::<font color=#0000ff>delete</font> p;
  }
};

<font color=#0000ff>class</font> UseResources {
  Cat* bp;
  Dog* op;

⌨️ 快捷键说明

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