chap03.htm.kbk

来自「c++设计思想」· KBK 代码 · 共 616 行 · 第 1/3 页

KBK
616
字号
an
object into that raw memory. The template parameters are the type of the output
iterator pointing to the raw storage, and the type of object that will be
stored. Here&#8217;s an example which creates <B>Noisy</B> objects (you&#8217;ll
be introduced to the <B>Noisy</B> class shortly; it&#8217;s not necessary to
know its details for this example):</FONT><BR></P></DIV>

<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#009900>//: C07:RawStorageIterator.cpp</font>
<font color=#009900>// Demonstrate the raw_storage_iterator</font>
<font color=#009900>//{L} ../TestSuite/Test</font>
<font color=#009900>//{-g++295} </font>
#include <font color=#004488>"Noisy.h"</font>
#include &lt;iostream&gt;
#include &lt;iterator&gt;
#include &lt;algorithm&gt;
<font color=#0000ff>using</font> <font color=#0000ff>namespace</font> std;

<font color=#0000ff>int</font> main() {
  <font color=#0000ff>const</font> <font color=#0000ff>int</font> quantity = 10;
  <font color=#009900>// Create raw storage and cast to desired type:</font>
  Noisy* np = 
    (Noisy*)<font color=#0000ff>new</font> <font color=#0000ff>char</font>[quantity * <font color=#0000ff>sizeof</font>(Noisy)];
  raw_storage_iterator&lt;Noisy*, Noisy&gt; rsi(np);
  <font color=#0000ff>for</font>(<font color=#0000ff>int</font> i = 0; i &lt; quantity; i++)
    *rsi++ = Noisy(); <font color=#009900>// Place objects in storage</font>
  cout &lt;&lt; endl;
  copy(np, np + quantity,
    ostream_iterator&lt;Noisy&gt;(cout, <font color=#004488>" "</font>));
  cout &lt;&lt; endl;
  <font color=#009900>// Explicit destructor call for cleanup:</font>
  <font color=#0000ff>for</font>(<font color=#0000ff>int</font> j = 0; j &lt; quantity; j++)
    (&amp;np[j])-&gt;~Noisy();
  <font color=#009900>// Release raw storage:</font>
  <font color=#0000ff>delete</font> (<font color=#0000ff>char</font>*)np;
} <font color=#009900>///:~</font></PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">To make the <B>raw_storage_iterator
</B>template happy, the raw storage must be of the same type as the objects
you&#8217;re creating. That&#8217;s why the pointer from the new array of
<B>char</B> is cast to a <B>Noisy*</B>. The assignment operator forces the
objects into the raw storage using the copy-constructor. Note that the explicit
destructor call must be made for proper cleanup, and this also allows the
objects to be deleted one at a time during container
manipulation.</FONT><A NAME="_Toc519042020"></A><BR></P></DIV>
<A NAME="Heading207"></A><FONT FACE = "Verdana, Tahoma, Arial, Helvetica, Sans"><H2 ALIGN="LEFT">
Basic sequences: <BR>vector, list &amp; deque</H2></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">If you take a step back from the STL
containers you&#8217;ll see that there are really only two types of container:
<I>sequences</I> (including <B>vector</B>, <B>list</B>, <B>deque</B>,
<B>stack</B>, <B>queue</B>, and <B>priority_queue</B>)<B> </B>and
<I>associations</I> (including <B>set</B>, <B>multiset</B>, <B>map</B> and
<B>multimap</B>). The sequences keep the objects in whatever sequence that you
establish (either by pushing the objects on the end or inserting them in the
middle).</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Since all the sequence containers have
the same basic goal (to maintain your order) they seem relatively
interchangeable. However, they differ in the efficiency of their operations, so
if you are going to manipulate a sequence in a particular fashion you can choose
the appropriate container for those types of manipulations. The
&#8220;basic&#8221; sequence containers are <B>vector</B>, <B>list</B> and
<B>deque</B> &#8211; these actually have fleshed-out implementations, while
<B>stack</B>, <B>queue</B> and <B>priority_queue</B> are built on top of the
basic sequences, and represent more specialized uses rather than differences in
underlying structure (<B>stack</B>, for example, can be implemented using a
<B>deque</B>, <B>vector</B> or <B>list</B>).</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">So far in this book I have been using
<B>vector</B> as a catch-all container. This was acceptable because I&#8217;ve
only used the simplest and safest operations, primarily <B>push_back(&#160;)</B>
and <B>operator[ ]</B>. However, when you start making more sophisticated uses
of containers it becomes important to know more about their underlying
implementations and behavior, so you can make the right choices (and, as
you&#8217;ll see, stay out of
trouble).</FONT><A NAME="_Toc519042021"></A><BR></P></DIV>
<A NAME="Heading208"></A><FONT FACE = "Verdana, Tahoma, Arial, Helvetica, Sans"><H3 ALIGN="LEFT">
Basic sequence operations</H3></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Using a template, the following example
shows the operations that all the basic sequences (<B>vector</B>, <B>deque</B>
or <B>list</B>) support. As you shall learn in the sections on the specific
sequence containers, not all of these operations make sense for each basic
sequence, but they are supported. </FONT><BR></P></DIV>

<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#009900>//: C07:BasicSequenceOperations.cpp</font>
<font color=#009900>// The operations available for all the </font>
<font color=#009900>// basic sequence Containers.</font>
<font color=#009900>//{L} ../TestSuite/Test</font>
<font color=#009900>//{-msc}</font>
#include &lt;iostream&gt;
#include &lt;vector&gt;
#include &lt;deque&gt;
#include &lt;list&gt;
<font color=#0000ff>using</font> <font color=#0000ff>namespace</font> std;

<font color=#0000ff>template</font>&lt;<font color=#0000ff>typename</font> Container&gt;
<font color=#0000ff>void</font> print(Container&amp; c, <font color=#0000ff>char</font>* s = <font color=#004488>""</font>) {
  cout &lt;&lt; s &lt;&lt; <font color=#004488>":"</font> &lt;&lt; endl;
  <font color=#0000ff>if</font>(c.empty()) {
    cout &lt;&lt; <font color=#004488>"(empty)"</font> &lt;&lt; endl;
    <font color=#0000ff>return</font>;
  }
  <font color=#0000ff>typename</font> Container::iterator it;
  <font color=#0000ff>for</font>(it = c.begin(); it != c.end(); it++)
    cout &lt;&lt; *it &lt;&lt; <font color=#004488>" "</font>;
  cout &lt;&lt; endl;
  cout &lt;&lt; <font color=#004488>"size() "</font> &lt;&lt; c.size() 
    &lt;&lt; <font color=#004488>" max_size() "</font>&lt;&lt; c.max_size() 
    &lt;&lt; <font color=#004488>" front() "</font> &lt;&lt; c.front()
    &lt;&lt; <font color=#004488>" back() "</font> &lt;&lt; c.back() &lt;&lt; endl;
}
  
<font color=#0000ff>template</font>&lt;<font color=#0000ff>typename</font> ContainerOfInt&gt;
<font color=#0000ff>void</font> basicOps(<font color=#0000ff>char</font>* s) {
  cout &lt;&lt; <font color=#004488>"------- "</font> &lt;&lt; s &lt;&lt; <font color=#004488>" -------"</font> &lt;&lt; endl;
  <font color=#0000ff>typedef</font> ContainerOfInt Ci;
  Ci c;
  print(c, <font color=#004488>"c after default constructor"</font>);
  Ci c2(10, 1); <font color=#009900>// 10 elements, values all 1</font>
  print(c2, <font color=#004488>"c2 after constructor(10,1)"</font>);
  <font color=#0000ff>int</font> ia[] = { 1, 3, 5, 7, 9 };
  <font color=#0000ff>const</font> <font color=#0000ff>int</font> iasz = <font color=#0000ff>sizeof</font>(ia)/<font color=#0000ff>sizeof</font>(*ia);
  <font color=#009900>// Initialize with begin &amp; end iterators:</font>
  Ci c3(ia, ia + iasz);
  print(c3, <font color=#004488>"c3 after constructor(iter,iter)"</font>);
  Ci c4(c2); <font color=#009900>// Copy-constructor</font>
  print(c4, <font color=#004488>"c4 after copy-constructor(c2)"</font>);
  c = c2; <font color=#009900>// Assignment operator</font>
  print(c, <font color=#004488>"c after operator=c2"</font>);
  c.assign(10, 2); <font color=#009900>// 10 elements, values all 2</font>
  print(c, <font color=#004488>"c after assign(10, 2)"</font>);
  <font color=#009900>// Assign with begin &amp; end iterators:</font>
  c.assign(ia, ia + iasz);
  print(c, <font color=#004488>"c after assign(iter, iter)"</font>);
  cout &lt;&lt; <font color=#004488>"c using reverse iterators:"</font> &lt;&lt; endl;
  <font color=#0000ff>typename</font> Ci::reverse_iterator rit = c.rbegin();
  <font color=#0000ff>while</font>(rit != c.rend())
    cout &lt;&lt; *rit++ &lt;&lt; <font color=#004488>" "</font>;
  cout &lt;&lt; endl;
  c.resize(4);
  print(c, <font color=#004488>"c after resize(4)"</font>);
  c.push_back(47);
  print(c, <font color=#004488>"c after push_back(47)"</font>);
  c.pop_back();
  print(c, <font color=#004488>"c after pop_back()"</font>);
  <font color=#0000ff>typename</font> Ci::iterator it = c.begin();
  it++; it++;
  c.insert(it, 74);
  print(c, <font color=#004488>"c after insert(it, 74)"</font>);
  it = c.begin();
  it++;
  c.insert(it, 3, 96);
  print(c, <font color=#004488>"c after insert(it, 3, 96)"</font>);
  it = c.begin();
  it++;
  c.insert(it, c3.begin(), c3.end());
  print(c, <font color=#004488>"c after insert("</font>
    <font color=#004488>"it, c3.begin(), c3.end())"</font>);
  it = c.begin();
  it++;
  c.erase(it);
  print(c, <font color=#004488>"c after erase(it)"</font>);
  <font color=#0000ff>typename</font> Ci::iterator it2 = it = c.begin();
  it++;
  it2++; it2++; it2++; it2++; it2++;
  c.erase(it, it2);
  print(c, <font color=#004488>"c after erase(it, it2)"</font>);
  c.swap(c2);
  print(c, <font color=#004488>"c after swap(c2)"</font>);
  c.clear();
  print(c, <font color=#004488>"c after clear()"</font>);
}

<font color=#0000ff>int</font> main() {
  basicOps&lt;vector&lt;<font color=#0000ff>int</font>&gt; &gt;(<font color=#004488>"vector"</font>);
  basicOps&lt;deque&lt;<font color=#0000ff>int</font>&gt; &gt;(<font color=#004488>"deque"</font>);
  basicOps&lt;list&lt;<font color=#0000ff>int</font>&gt; &gt;(<font color=#004488>"list"</font>);
} <font color=#009900>///:~</font></PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The first function template,
<B>print(&#160;)</B>, demonstrates the basic information you can get from any
sequence container: whether it&#8217;s empty, its current size, the size of the
largest possible container, the element at the beginning and the element at the
end. You can also see that every container has <B>begin(&#160;)</B> and
<B>end(&#160;)</B> methods that return iterators.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The <B>basicOps(&#160;)</B> function
tests everything else (and in turn calls <B>print(&#160;)</B>), including a
variety of constructors: default, copy-constructor, quantity and initial value,
and beginning and ending iterators. There&#8217;s an assignment <B>operator=</B>
and two kinds of <B>assign(&#160;)</B> member functions, one which takes a
quantity and initial value and the other which take a beginning and ending
iterator.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">All the basic sequence containers are
reversible containers, as shown by the use of the <B>rbegin(&#160;)</B> and
<B>rend(&#160;)</B> member functions. A sequence container can be resized, and
the entire contents of the container can be removed with
<B>clear(&#160;)</B>.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Using an iterator to indicate where you
want to start inserting into any sequence container, you can
<B>insert(&#160;)</B> a single element, a number of elements that all have the
same value, and a group of elements from another container using the beginning
and ending iterators of that group. </FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">To <B>erase(&#160;)</B> a single element
from the middle, use an iterator; to <B>erase(&#160;)</B> a range of elements,
use a pair of iterators. Notice that since a <B>list</B> only supports
bidirectional iterators, all the iterator motion must be performed with
increments and decrements (if the containers were limited to <B>vector </B>and
<B>deque</B>, which produce random-access iterators, then <B>operator+</B> and
<B>operator-</B> could have been used to move the iterators in big
jumps).</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Although both <B>list</B> and

⌨️ 快捷键说明

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