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

📄 index.html

📁 C程序员手册(英文)
💻 HTML
📖 第 1 页 / 共 5 页
字号:
</pre>
<p>On most implementations, the parameterized types <tt>size_type</tt> and <tt>difference_type</tt> 
  have the default values <tt>size_t</tt> and <tt>ptrdiff_t</tt>, respectively. 
  However, they can be replaced by other types for particular specializations.</p>
<p>The storage of STL containers automatically grows as necessary, freeing the 
  programmer from this tedious and error-prone task. For example, a <tt>vector</tt> 
  can be used to read an unknown number of elements from the keyboard:</p>
<pre>
<tt>#include &lt;vector&gt;</tt>
<tt>#include &lt;iostream&gt;</tt>
<tt>using namespace std;</tt>
<tt>int main()</tt>
<tt>{</tt>
<tt>  vector &lt;int&gt; vi;</tt>
<tt>  for (;;) //read numbers from a user's console until 0 is input</tt>
<tt>  {</tt>
<tt>    int temp;</tt>
<tt>    cout&lt;&lt;"enter a number; press 0 to terminate" &lt;&lt;endl;</tt>
<tt>    cin&gt;&gt;temp;</tt>
<tt>    if (temp == 0 ) break; //exit from loop?</tt>
<tt>    vi.push_back(temp); //insert int into the buffer</tt>
<tt>  }</tt>
<tt>  cout&lt;&lt; "you entered "&lt;&lt; vi.size() &lt;&lt;" elements" &lt;&lt;endl;</tt>
<tt>  return 0;</tt>
<tt>}//end main</tt>
</pre>
<h3> <a name="Heading13">Container Reallocation</a></h3>
<p>The memory allocation scheme of STL containers must address two conflicting 
  demands. On the one hand, a container should not preallocate large amounts of 
  memory because it can impair the system's performance. On the other hand, it 
  is inefficient to allow a container reallocate memory whenever it stores a few 
  more elements. The allocation strategy has to walk a thin line. On many implementations, 
  a container initially allocates a small memory buffer, which grows exponentially 
  with every reallocation. Sometimes, however, it is possible to estimate in advance 
  how many elements the container will have to store. In this case, the user can 
  preallocate a sufficient amount of memory in advance so that the recurrent reallocation 
  process can be avoided. Imagine a mail server of some Internet Service Provider: 
  The server is almost idle at 4 a.m. At 9 a.m., however, it has to transfer thousands 
  of emails every minute. The incoming emails are first stored in a <tt>vector</tt> 
  before they are routed to other mail servers across the Web. Allowing the container 
  to reallocate itself little by little with every few dozen emails can degrade 
  performance.</p>
<h4> What Happens During Reallocation?</h4>
<p>The reallocation process consists of four steps. First, a new memory buffer 
  that is large enough to store the container is allocated. Second, the existing 
  elements are copied to the new memory location. Third, the destructors of the 
  elements in their previous location are successively invoked. Finally, the original 
  memory buffer is released. Obviously, reallocation is a costly operation. You 
  can avert reallocation by calling the member function <tt>reserve()</tt>. <tt>reserve(</tt><cite>n</cite><tt>)</tt> 
  ensures that the container reserves sufficient memory for at least <cite>n</cite> 
  elements in advance, as in the following example:</p>
<pre>
<tt>class Message { /*...*/};</tt>
<tt>#include &lt;vector&gt;</tt>
<tt>using namespace std;</tt>
<tt>int FillWithMessages(vector&lt;Message&gt;&amp; msg_que); //severe time constraints</tt>
<tt>int main()</tt>
<tt>{</tt>
<tt>  vector &lt;Message&gt; msgs;</tt>
<tt>  // before entering a time-critical section, make room for 1000 Messages</tt>
<tt>  msgs.reserve(1000);</tt>
<tt>//no re-allocation should occur before 1000 objects have been stored in vector</tt>
<tt>  FillWithMessages(msgs);</tt>
<tt>  return 0;</tt>
<tt>}</tt>
</pre>
<h3> <a name="Heading14">capacity() and size()</a></h3>
<p><tt>capacity()</tt> returns the total number of elements that the container 
  can hold without requiring reallocation. <tt>size()</tt> returns the number 
  of elements that are currently stored in the container. In other words, <tt>capacity() 
  - size()</tt> is the number of available "free slots" that can be filled with 
  additional elements without reallocating. The capacity of a container can be 
  resized explicitly by calling either <tt>reserve()</tt> or <tt>resize()</tt>. 
  These member functions differ in two respects. <tt>resize(</tt><cite>n</cite><tt>)</tt> 
  allocates memory for <cite>n</cite> objects and default-initializes them (you 
  can provide a different initializer value as the second optional argument). 
</p>
<p><tt>reserve()</tt> allocates raw memory without initializing it. In addition, 
  <tt>reserve()</tt> does not change the value that is returned from <tt>size()</tt> 
  it only changes the value that is returned from <tt>capacity</tt>(). <tt>resize()</tt> 
  changes both these values. For example</p>
<pre>
<tt>#include &lt;iostream&gt;</tt>
<tt>#include &lt;vector&gt;</tt>
<tt>#include &lt;string&gt;</tt>
<tt>using namespace std;</tt>
<tt>int main()</tt>
<tt>{</tt>
<tt>  vector &lt;string&gt; vs;</tt>
<tt>  vs.reserve(10);  //make room for at least 10 more strings</tt>
<tt>  vs.push_back(string()); //insert an element   </tt>
<tt>  cout&lt;&lt;"size: "&lt;&lt; vs.size()&lt;&lt;endl; //output: 1</tt>
<tt>  cout&lt;&lt;"capacity: "&lt;&lt;vs.capacity()&lt;&lt;endl; //output: 10</tt>
<tt>  cout&lt;&lt;"there's room for "&lt;&lt;vs.capacity() - vs.size()</tt>
<tt>      &lt;&lt;" elements before reallocation"&lt;&lt;endl;</tt>
<tt>  //allocate 10 more elements, initialized each with string::string()</tt>
<tt>  vs.resize(20);</tt>
<tt>  cout&lt;&lt;"size: "&lt;&lt; vs.size()&lt;&lt;endl; //output 20</tt>
<tt>  cout&lt;&lt;"capacity: "&lt;&lt;vs.capacity()&lt;&lt;endl; //output 20;</tt>
<tt>  return 0;</tt>
<tt>}</tt>
</pre>
<h3> <a name="Heading15">Specifying the Container's Capacity During Construction</a></h3>
<p>Up until now, the examples in this chapter have used explicit operations to 
  preallocate storage by calling either <tt>reserve()</tt> or <tt>resize()</tt>. 
  However, it is possible to specify the requested storage size during construction. 
  For example</p>
<pre>
<tt>#include &lt;vector&gt;</tt>
<tt>using namespace std;</tt>
<tt>int main()</tt>
<tt>{</tt>
<tt>  vector&lt;int&gt;  vi(1000); //initial storage for 1000 int's</tt>
<tt>  //vi contains 1000 elements initialized by int::int()</tt>
<tt>  return 0;</tt>
<tt>}</tt>
</pre>
<p>Remember that <tt>reserve()</tt> allocates raw memory without initializing 
  it. The constructor, on the other hand, initializes the allocated elements by 
  invoking their default constructor. It is possible to specify a different initializer 
  value, though:</p>
<pre>
<tt>vector&lt;int&gt;  vi(1000, 4); //initial  all 1000 int's with 4</tt>
</pre>
<h3> <a name="Heading16">Accessing a Single Element</a></h3>
<p>The overloaded operator <tt>[]</tt> and the member function <tt>at()</tt> enable 
  direct access to a vector's element. Both have a <tt>const</tt> and a non-<tt>const</tt> 
  version, so they can be used to access an element of a <tt>const</tt> and a 
  non-<tt>const</tt> vector, respectively.</p>
<p>The overloaded <tt>[]</tt> operator was designed to be as efficient as its 
  built-in counterpart. Therefore, <tt>[]</tt> does not check to see if its argument 
  actually refers to a valid element. The lack of runtime checks ensures the fastest 
  access time (an operator <tt>[]</tt> call is usually inlined). However, using 
  operator <tt>[]</tt> with an illegal subscript yields undefined behavior. When 
  performance is paramount, and when the code is written carefully so that only 
  legal subscripts are accessed, use the <tt>[]</tt> operator. The <tt>[]</tt> 
  notation is also more readable and intuitive. Nonetheless, runtime checks are 
  unavoidable in some circumstances for instance, when the subscript value is 
  received from an external source such as a function, a database record, or a 
  human operator. In such cases you should use the member function <tt>at()</tt> 
  instead of operator <tt>[]</tt>. <tt>at()</tt> performs range checking and, 
  in case of an attempt to access an out of range member, it throws an exception 
  of type <tt>std::out_of_range</tt>. Here is an example:</p>
<pre>
<tt>#include &lt;vector&gt;</tt>
<tt>#include &lt;iostream&gt;</tt>
<tt>#include &lt;string&gt;</tt>
<tt>#include &lt;stdexcept&gt;</tt>
<tt>using namespace std;</tt>
<tt>int main()</tt>
<tt>{</tt>
<tt>  vector&lt;string&gt; vs; // vs has no elements currently</tt>
<tt>  vs.push_back("string"); //add first element</tt>
<tt>  vs[0] = "overriding string"; //override it using []</tt>
<tt>  try</tt>
<tt>  {</tt>
<tt>    cout&lt;&lt; vs.at(10) &lt;&lt;endl; //out of range element, exception thrown</tt>
<tt>  }</tt>
<tt>  catch(std::out_of_range &amp; except)</tt>
<tt>  {</tt>
<tt>    // handle out-of-range subscript</tt>
<tt>  }</tt>
<tt>}//end main</tt>
</pre>
<h3> <a name="Heading17">Front and Back Operations</a></h3>
<p>Front and back operations refer to the beginning and the end of a container, 
  respectively. The member function <tt>push_back()</tt> appends a single element 
  to the end of the container. When the container has exhausted its free storage, 
  it reallocates additional storage, and then appends the element. The member 
  function <tt>pop_back()</tt> removes the last element from the container. The 
  member functions <tt>front()</tt> and <tt>back()</tt> access a single element 
  at the container's beginning and end, respectively. <tt>front()</tt> and <tt>back()</tt> 
  both have a <tt>const</tt> and a non-<tt>const</tt> version. For example</p>
<pre>
<tt>#include &lt;iostream&gt;</tt>
<tt>#include &lt;vector&gt;</tt>
<tt>using namespace std;</tt>
<tt>int main()</tt>
<tt>{</tt>
<tt>  vector &lt;short&gt; v;</tt>
<tt>  v.push_back(5);</tt>
<tt>  v.push_back(10);</tt>
<tt>  cout&lt;&lt;"front: " &lt;&lt; v.front() &lt;&lt; endl; //5</tt>
<tt>  cout&lt;&lt;"back: " &lt;&lt; v.back() &lt;&lt; endl; //10</tt>
<tt>  v.pop_back(); //remove v[1]</tt>
<tt>  cout&lt;&lt;"back: " &lt;&lt; v.back() &lt;&lt; endl; //now 5</tt>
<tt>  return 0;</tt>
<tt>}</tt>
</pre>
<h3> <a name="Heading18">Container Assignment</a></h3>
<p>STL containers overload the assignment operator, thereby allowing containers 
  of the same type to be assigned easily. For example</p>
<pre>
<tt>#include &lt;iostream&gt;</tt>
<tt>#include&lt;vector&gt;</tt>
<tt>using namespace std;</tt>
<tt>int main()</tt>
<tt>{</tt>
<tt>  vector &lt;int&gt; vi;</tt>
<tt>  vi.push_back(1);</tt>
<tt>  vi.push_back(2);</tt>
<tt>  vector &lt;int&gt; new_vector;</tt>
<tt>  //copy the contents of vi to new_vector, which automatically grows as needed</tt>
<tt>  new_vector = vi;</tt>
<tt>  cout &lt;&lt; new_vector[0] &lt;&lt; new_vector[1] &lt;&lt; endl;   // display 1 and 2</tt>
<tt>  return 0; </tt>
<tt>} </tt>
</pre>
<h3> <a name="Heading19">Contiguity of Vectors</a></h3>
<p>Built-in arrays in C++ reside in contiguous chunks of memory. The Standard, 
  however, does not require that vector elements occupy contiguous memory. When 
  STL was added to the Standard, it seemed intuitive that vectors should store 
  their elements contiguously, so contiguity never became an explicit requirement. 
  Indeed, all current STL implementations follow this convention. The current 
  specification, however, permits implementations that do not use contiguous memory. 
  This loophole will probably be fixed by the Standardization committee in the 
  future, and vector contiguity will become a Standard requirement.</p>
<h3> <a name="Heading20">A vector&lt;Base&gt; Should not Store Derived Objects</a></h3>
<p>Each element in a vector must have the same size. Because a derived object 
  can have additional members, its size might be larger than the size of its base 
  class. Avoid storing a derived object in a <tt>vector&lt;Base&gt;</tt> because 
  it can cause object slicing with undefined results. You can, however, achieve 
  the desired polymorphic behavior by storing a pointer to a derived object in 
  a <tt>vector&lt;Base*&gt;.</tt></p>
<h3> <a name="Heading21">FIFO Data Models</a></h3>
<p>In a queue data model (a queue is also called FIFO first in first out), the 
  first element that is inserted is located at the topmost position, and any subsequent 
  elements are located at lower positions. The two basic operations in a queue 
  are <tt>pop()</tt> and <tt>push()</tt>. A <tt>push()</tt> operation inserts 
  an element into the bottom of the queue. A <tt>pop()</tt> operation removes 
  the element at the topmost position, which was the first to be inserted; consequently, 
  the element that is located one position lower becomes the topmost element. 
  The STL <tt>queue</tt> container can be used as follows:</p>
<pre>
<tt>#include &lt;iostream&gt;</tt>
<tt>#include &lt;queue&gt;</tt>
<tt>using namespace std;</tt>
<tt>int main()</tt>
<tt>{</tt>
<tt> queue &lt;int&gt; iq;</tt>
<tt> iq.push(93); //insert the first element, it is the top-most one</tt>
<tt> iq.push(250);</tt>
<tt> iq.push(10); //last element inserted is located at the bottom</tt>
<tt> cout&lt;&lt;"currently there are "&lt;&lt; iq.size() &lt;&lt; " elements" &lt;&lt; endl;</tt>
<tt> while (!iq.empty() )</tt>
<tt> {</tt>
<tt>   cout &lt;&lt;"the last element is: "&lt;&lt; iq.front() &lt;&lt; endl; //front() returns </tt>
<tt>                                                        //the top-most element</tt>
<tt>  iq.pop(); //remove the top-most element</tt>
<tt> }</tt>
<tt> return 0;</tt>
<tt>}</tt>
</pre>
<p>STL also defines a double-ended queue, or <i>deque</i> (pronounced "deck") 
  container. A <tt>deque</tt> is a queue that is optimized to support operations 
  at both ends efficiently. Another type of queue is a <cite>priority_queue</cite>. 
  A <tt>priority_queue</tt> has all its elements internally sorted according to 
  their priority. The element with the highest priority is located at the top. 
  To qualify as an element of <tt>priority_queue</tt>, an object has to define 

⌨️ 快捷键说明

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