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

📄 chapter06.html

📁 《C++编程思想》中文版。。。。。。。。。。。。。
💻 HTML
📖 第 1 页 / 共 5 页
字号:

<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#009900>//: C06:Nojump.cpp</font>
<font color=#009900>// Can't jump past constructors</font>

<font color=#0000ff>class</font> X {
<font color=#0000ff>public</font>:
  X();
};

X::X() {}

<font color=#0000ff>void</font> f(<font color=#0000ff>int</font> i) {
  <font color=#0000ff>if</font>(i &lt; 10) {
   <font color=#009900>//! goto jump1; // Error: goto bypasses init</font>
  }
  X x1;  <font color=#009900>// Constructor called here</font>
 jump1:
  <font color=#0000ff>switch</font>(i) {
    <font color=#0000ff>case</font> 1 :
      X x2;  <font color=#009900>// Constructor called here</font>
      <font color=#0000ff>break</font>;
  <font color=#009900>//! case 2 : // Error: case bypasses init</font>
      X x3;  <font color=#009900>// Constructor called here</font>
      <font color=#0000ff>break</font>;
  }
} 

<font color=#0000ff>int</font> main() {
  f(9);
  f(11);
}<font color=#009900>///:~ </font></PRE></FONT></BLOCKQUOTE>

<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">In the code above, both the <B>goto</B>
and the <B>switch</B> can potentially jump past the sequence point where a
constructor is called. That object will then be in scope even if the constructor
hasn&#8217;t been called, so the compiler gives an error message. This once
again guarantees <A NAME="Index1338"></A><A NAME="Index1339"></A>that an object
cannot be created unless it is also initialized.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">All the storage allocation discussed here
happens, of course, on the stack<A NAME="Index1340"></A>. The storage is
allocated by the compiler by moving the stack pointer &#8220;down&#8221; (a
relative term, which may indicate an increase or decrease of the actual stack
pointer <A NAME="Index1341"></A>value, depending on your machine). Objects can
also be allocated on the heap using <B>new</B>, which is something we&#8217;ll
explore further in Chapter
13.</FONT><A NAME="_Toc312373858"></A><A NAME="_Toc472654858"></A><BR></P></DIV>
<A NAME="Heading230"></A><FONT FACE = "Verdana"><H2 ALIGN="LEFT">
Stash with constructors and destructors</H2></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The examples from previous chapters have
obvious functions that map to constructors and destructors:
<B>initialize(&#160;)</B> and <B>cleanup(&#160;)</B>. Here&#8217;s the
<B>Stash</B> header using constructors and destructors:
<A NAME="Index1342"></A></FONT><BR></P></DIV>

<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#009900>//: C06:Stash2.h</font>
<font color=#009900>// With constructors &amp; destructors</font>
#ifndef STASH2_H
#define STASH2_H

<font color=#0000ff>class</font> Stash {
  <font color=#0000ff>int</font> size;      <font color=#009900>// Size of each space</font>
  <font color=#0000ff>int</font> quantity;  <font color=#009900>// Number of storage spaces</font>
  <font color=#0000ff>int</font> next;      <font color=#009900>// Next empty space</font>
  <font color=#009900>// Dynamically allocated array of bytes:</font>
  <font color=#0000ff>unsigned</font> <font color=#0000ff>char</font>* storage;
  <font color=#0000ff>void</font> inflate(<font color=#0000ff>int</font> increase);
<font color=#0000ff>public</font>:
  Stash(<font color=#0000ff>int</font> size);
  ~Stash();
  <font color=#0000ff>int</font> add(<font color=#0000ff>void</font>* element);
  <font color=#0000ff>void</font>* fetch(<font color=#0000ff>int</font> index);
  <font color=#0000ff>int</font> count();
};
#endif <font color=#009900>// STASH2_H ///:~</font></PRE></FONT></BLOCKQUOTE>

<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The only member function definitions that
are changed are <B>initialize(&#160;)</B> and <B>cleanup(&#160;)</B>, which have
been replaced with a constructor and destructor:</FONT><BR></P></DIV>

<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#009900>//: C06:Stash2.cpp {O}</font>
<font color=#009900>// Constructors &amp; destructors</font>
#include <font color=#004488>"Stash2.h"</font>
#include <font color=#004488>"../require.h"</font>
#include &lt;iostream&gt;
#include &lt;cassert&gt;
<font color=#0000ff>using</font> <font color=#0000ff>namespace</font> std;
<font color=#0000ff>const</font> <font color=#0000ff>int</font> increment = 100;

Stash::Stash(<font color=#0000ff>int</font> sz) {
  size = sz;
  quantity = 0;
  storage = 0;
  next = 0;
}

<font color=#0000ff>int</font> Stash::add(<font color=#0000ff>void</font>* element) {
  <font color=#0000ff>if</font>(next &gt;= quantity) <font color=#009900>// Enough space left?</font>
    inflate(increment);
  <font color=#009900>// Copy element into storage,</font>
  <font color=#009900>// starting at next empty space:</font>
  <font color=#0000ff>int</font> startBytes = next * size;
  <font color=#0000ff>unsigned</font> <font color=#0000ff>char</font>* e = (<font color=#0000ff>unsigned</font> <font color=#0000ff>char</font>*)element;
  <font color=#0000ff>for</font>(<font color=#0000ff>int</font> i = 0; i &lt; size; i++)
    storage[startBytes + i] = e[i];
  next++;
  <font color=#0000ff>return</font>(next - 1); <font color=#009900>// Index number</font>
}

<font color=#0000ff>void</font>* Stash::fetch(<font color=#0000ff>int</font> index) {
  require(0 &lt;= index, <font color=#004488>"Stash::fetch (-)index"</font>);
  <font color=#0000ff>if</font>(index &gt;= next)
    <font color=#0000ff>return</font> 0; <font color=#009900>// To indicate the end</font>
  <font color=#009900>// Produce pointer to desired element:</font>
  <font color=#0000ff>return</font> &amp;(storage[index * size]);
}

<font color=#0000ff>int</font> Stash::count() {
  <font color=#0000ff>return</font> next; <font color=#009900>// Number of elements in CStash</font>
}

<font color=#0000ff>void</font> Stash::inflate(<font color=#0000ff>int</font> increase) {
  require(increase &gt; 0, 
    <font color=#004488>"Stash::inflate zero or negative increase"</font>);
  <font color=#0000ff>int</font> newQuantity = quantity + increase;
  <font color=#0000ff>int</font> newBytes = newQuantity * size;
  <font color=#0000ff>int</font> oldBytes = quantity * size;
  <font color=#0000ff>unsigned</font> <font color=#0000ff>char</font>* b = <font color=#0000ff>new</font> <font color=#0000ff>unsigned</font> <font color=#0000ff>char</font>[newBytes];
  <font color=#0000ff>for</font>(<font color=#0000ff>int</font> i = 0; i &lt; oldBytes; i++)
    b[i] = storage[i]; <font color=#009900>// Copy old to new</font>
  <font color=#0000ff>delete</font> [](storage); <font color=#009900>// Old storage</font>
  storage = b; <font color=#009900>// Point to new memory</font>
  quantity = newQuantity;
}

Stash::~Stash() {
  <font color=#0000ff>if</font>(storage != 0) {
   cout &lt;&lt; <font color=#004488>"freeing storage"</font> &lt;&lt; endl;
   <font color=#0000ff>delete</font> []storage;
  }
} <font color=#009900>///:~</font></PRE></FONT></BLOCKQUOTE>

<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">You can see that the <B>require.h</B>
functions are being used to watch for programmer errors, instead of
<B>assert(&#160;)</B>. The output of a failed <B>assert(&#160;)</B> is not as
useful as that of the <B>require.h</B> functions (which will be shown later in
the book).</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Because <B>inflate(&#160;)</B> is
private, the only way a <B>require(&#160;)</B> could fail is if one of the other
member functions accidentally passed an incorrect value to
<B>inflate(&#160;)</B>. If you are certain this can&#8217;t happen, you could
consider removing the <B>require(&#160;)</B>, but you might keep in mind that
until the class is stable, there&#8217;s always the possibility that new code
might be added to the class that could cause errors. The cost of the
<B>require(&#160;)</B> is low (and could be automatically removed using the
preprocessor) and the value of code robustness is high.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Notice in the following test program how
the definitions for <B>Stash</B> objects appear right before they are needed,
and how the initialization appears as part of the definition, in the constructor
argument list:</FONT><BR></P></DIV>

<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#009900>//: C06:Stash2Test.cpp</font>
<font color=#009900>//{L} Stash2</font>
<font color=#009900>// Constructors &amp; destructors</font>
#include <font color=#004488>"Stash2.h"</font>
#include <font color=#004488>"../require.h"</font>
#include &lt;fstream&gt;
#include &lt;iostream&gt;
#include &lt;string&gt;
<font color=#0000ff>using</font> <font color=#0000ff>namespace</font> std;

<font color=#0000ff>int</font> main() {
  Stash intStash(<font color=#0000ff>sizeof</font>(<font color=#0000ff>int</font>));
  <font color=#0000ff>for</font>(<font color=#0000ff>int</font> i = 0; i &lt; 100; i++)
    intStash.add(&amp;i);
  <font color=#0000ff>for</font>(<font color=#0000ff>int</font> j = 0; j &lt; intStash.count(); j++)
    cout &lt;&lt; <font color=#004488>"intStash.fetch("</font> &lt;&lt; j &lt;&lt; <font color=#004488>") = "</font>
         &lt;&lt; *(<font color=#0000ff>int</font>*)intStash.fetch(j)
         &lt;&lt; endl;
  <font color=#0000ff>const</font> <font color=#0000ff>int</font> bufsize = 80;
  Stash stringStash(<font color=#0000ff>sizeof</font>(<font color=#0000ff>char</font>) * bufsize);
  ifstream in(<font color=#004488>"Stash2Test.cpp"</font>);
  assure(in, <font color=#004488>" Stash2Test.cpp"</font>);
  string line;
  <font color=#0000ff>while</font>(getline(in, line))
    stringStash.add((<font color=#0000ff>char</font>*)line.c_str());
  <font color=#0000ff>int</font> k = 0;
  <font color=#0000ff>char</font>* cp;
  <font color=#0000ff>while</font>((cp = (<font color=#0000ff>char</font>*)stringStash.fetch(k++))!=0)
    cout &lt;&lt; <font color=#004488>"stringStash.fetch("</font> &lt;&lt; k &lt;&lt; <font color=#004488>") = "</font>
         &lt;&lt; cp &lt;&lt; endl;
} <font color=#009900>///:~</font></PRE></FONT></BLOCKQUOTE>

<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Also notice how the
<B>cleanup(&#160;)</B> calls have been eliminated, but the
<A NAME="Index1343"></A>destructors are still automatically
<A NAME="Index1344"></A>called when <B>intStash</B> and <B>stringStash</B> go
out of scope.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">One thing to be aware of in the
<B>Stash</B> examples: I&#8217;m being very careful to use only built-in types;
that is, those without destructors. If you were to try to copy class objects
into the <B>Stash</B>, you&#8217;d run into all kinds of problems and it
wouldn&#8217;t work right. The Standard C++ Library can actually make correct
copies of objects into its containers, but this is a rather messy and
complicated process. In the following <B>Stack</B> example, you&#8217;ll see
that pointers are used to sidestep this issue, and in a later chapter the
<B>Stash</B> will be converted so that it uses
pointers.</FONT><A NAME="_Toc312373859"></A><A NAME="_Toc472654859"></A><BR></P></DIV>
<A NAME="Heading231"></A><FONT FACE = "Verdana"><H2 ALIGN="LEFT">
Stack with constructors &amp; destructors</H2></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Reimplementing the linked list
<A NAME="Index1345"></A><A NAME="Index1346"></A>(inside <B>Stack</B>)<B>
</B>with constructors and destructors shows how neatly constructors and
destructors work with <B>new </B>and <B>delete</B>. Here&#8217;s the modified
header file: <A NAME="Index1347"></A></FONT><BR></P></DIV>

<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#009900>//: C06:Stack3.h</font>

⌨️ 快捷键说明

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