blob: fae60c839d95edefd6e9ec681c4c253f45885039 [file] [log] [blame]
<!--
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed
with this work for additional information regarding copyright
ownership. The ASF licenses this file to you under the Apache
License, Version 2.0 (the License); you may not use this file
except in compliance with the License. You may obtain a copy of
the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied. See the License for the specific language governing
permissions and limitations under the License.
Copyright 1999-2007 Rogue Wave Software, Inc.
-->
<HTML>
<HEAD>
<TITLE>Initialization Algorithms</TITLE>
<LINK REL=StyleSheet HREF="../rw.css" TYPE="text/css" TITLE="Apache stdcxx Stylesheet"></HEAD>
<BODY BGCOLOR=#FFFFFF>
<A HREF="13-1.html"><IMG SRC="images/bprev.gif" WIDTH=20 HEIGHT=21 ALT="Previous file" BORDER=O></A><A HREF="noframes.html"><IMG SRC="images/btop.gif" WIDTH=56 HEIGHT=21 ALT="Top of Document" BORDER=O></A><A HREF="booktoc.html"><IMG SRC="images/btoc.gif" WIDTH=56 HEIGHT=21 ALT="Contents" BORDER=O></A><A HREF="tindex.html"><IMG SRC="images/bindex.gif" WIDTH=56 HEIGHT=21 ALT="Index page" BORDER=O></A><A HREF="13-3.html"><IMG SRC="images/bnext.gif" WIDTH=25 HEIGHT=21 ALT="Next file" BORDER=O></A><DIV CLASS="DOCUMENTNAME"><B>Apache C++ Standard Library User's Guide</B></DIV>
<H2>13.2 Initialization Algorithms</H2>
<A NAME="idx252"><!></A>
<A NAME="idx253"><!></A>
<P>The first set of algorithms we cover are used chiefly, although not exclusively, to initialize a newly created sequence with certain values. The C++ Standard Library provides several initialization algorithms. The initialization algorithms all overwrite every element in a container. The difference between the algorithms is the source for the values used in initialization. The <SAMP>std::fill()</SAMP> algorithm repeats a single value, the <SAMP>std::copy()</SAMP> algorithm reads values from a second container, and the <SAMP>std::generate()</SAMP> algorithm invokes a function for each new value. In our discussion we provide examples of how to apply these algorithms, and suggest how to choose one algorithm over another.</P>
<BLOCKQUOTE><HR><B>
NOTE -- The sample programs described in the following sections are in the file alg1.cpp. We generally omit output statements from the descriptions of the programs provided here, although they are included in the compete versions.
</B><HR></BLOCKQUOTE>
<A NAME="1321"><H3>13.2.1 Fill a Sequence with An Initial Value</H3></A>
<A NAME="idx254"><!></A>
<P>The <SAMP>std::fill()</SAMP> and <SAMP>std::fill_n()</SAMP> algorithms are used to initialize or reinitialize a sequence with a fixed value. Their declarations are as follows:</P>
<UL><PRE>
namespace std {
void fill(ForwardIterator first,
ForwardIterator last, const T&amp;);
void fill_n(OutputIterator, Size, const T&amp;);
}
</PRE></UL>
<A NAME="idx255"><!></A>
<P>The example program illustrates several uses of the algorithm:</P>
<A NAME="idx259"><!></A>
<A NAME="idx258"><!></A>
<A NAME="idx257"><!></A>
<A NAME="idx256"><!></A>
<UL><PRE>
void fill_example ()
// illustrates the use of the fill algorithm
// see alg1.cpp for complete source code
{
// example 1, fill an array with initial values
char buffer[100], *bufferp = buffer;
std::fill(bufferp, bufferp + 100, '\0');
std::fill_n(bufferp, 10, 'x');
// example 2, use fill_n to initialize a list
std::list&lt;string&gt; aList(5, "nothing");
std::fill_n(inserter(aList, aList.begin()), 10, "empty");
// example 3, use fill to overwrite values in list
std::fill(aList.begin(), aList.end(), "full");
// example 4, fill in a portion of a collection
std::vector&lt;int&gt; iVec(10);
std::generate(iVec.begin(), iVec.end(), iotaGen(1));
std::vector&lt;int&gt;::iterator&amp; seven =
std::find(iVec.begin(), iVec.end(), 7);
std::fill(iVec.begin(), seven, 0);
}
</PRE></UL>
<P>In example 1, an array of character values is declared. The <SAMP>std::fill()</SAMP> algorithm is invoked to initialize each location in this array with a null character value. The first 10 positions are then replaced with the character <SAMP>'x'</SAMP> by using the algorithm <SAMP>std::fill_n()</SAMP>. Note that the <SAMP>std::fill()</SAMP> algorithm requires both starting and past-end <B><I><A HREF="../stdlibref/iterator.html">iterator</A></I></B>s as arguments, whereas the <SAMP>std::fill_n()</SAMP> algorithm uses a starting <B><I>iterator</I></B> and a count.</P>
<A NAME="idx260"><!></A>
<P>By applying an <I>insert iterator</I> (<A HREF="2-4.html">Section&nbsp;2.4</A>), example 2 illustrates how the <SAMP>std::fill_n()</SAMP> algorithm can be used to initialize a variable length container, such as a <B><I><A HREF="../stdlibref/list.html">list</A></I></B>. In this case the <B><I>list</I></B> initially contains five elements, all holding the text <SAMP>"nothing"</SAMP>. The call on <SAMP>std::fill_n()</SAMP> then inserts ten instances of the string <SAMP>"empty"</SAMP>. The resulting <B><I>list</I></B> contains fifteen elements.</P>
<P>Examples 3 and 4 illustrate how <SAMP>std::fill()</SAMP> can be used to change the values in an existing container. In example 3 each of the fifteen elements in the <B><I><A HREF="../stdlibref/list.html">list</A></I></B> created in example 2 is replaced by the string <SAMP>"full"</SAMP>. </P>
<P>Example 4 overwrites only a portion of a <B><I><A HREF="../stdlibref/list.html">list</A></I></B>. Using the generic algorithm <SAMP>std::generate()</SAMP> and the function object <B><I>iotaGen</I></B> (see <A HREF="3-2.html">Section&nbsp;3.2</A> and <A HREF="13-2.html#1323">Section&nbsp;13.2.3</A>), a vector is initialized to the values <SAMP>1 2 3... 10</SAMP>. The <SAMP>std::find()</SAMP> algorithm (see <A HREF="13-3.html#1331">Section&nbsp;13.3.1</A>) is used to locate the position of the element 7, saving the location in an iterator appropriate for the <B><I><A HREF="../stdlibref/vector.html">vector</A></I></B> datatype. The<SAMP> std::fill()</SAMP> call then replaces all values up to, but not including, the <SAMP>7</SAMP> entry with the value <SAMP>0</SAMP>. The resulting vector has six zero fields, followed by the values <SAMP>7</SAMP>, <SAMP>8</SAMP>, <SAMP>9</SAMP> and <SAMP>10</SAMP>.</P>
<P>The <SAMP>std::fill()</SAMP> and<SAMP> std::fill_n()</SAMP> algorithm can be used with all the container classes contained in the C++ Standard Library, although insert iterators must be used with ordered containers, such as <B><I><A HREF="../stdlibref/set.html">set</A></I></B>s.</P>
<A NAME="1322"><H3>13.2.2 Copy One Sequence Into Another Sequence</H3></A>
<A NAME="idx261"><!></A>
<P>The algorithms <SAMP>std::copy()</SAMP> and <SAMP>std::copy_backward()</SAMP> are versatile functions that can be used for a number of different purposes, and are probably the most commonly executed algorithms in the C++ Standard Library. The declarations for these algorithms are as follows:</P>
<UL><PRE>
namespace std {
OutputIterator copy (InputIterator first, InputIterator last,
OutputIterator result);
BidirectionalIterator copy_backward
(BidirectionalIterator first, BidirectionalIterator last,
BidirectionalIterator result);
}
</PRE></UL>
<A NAME="idx262"><!></A>
<P>The result returned by the <SAMP>copy()</SAMP> function is a pointer to the end of the copied sequence. However, the result of one <SAMP>copy()</SAMP> operation can be used as a starting iterator in a subsequent <SAMP>copy()</SAMP> to make a <I>catenation</I> of values.</P>
<P>Uses of the copy algorithm include:</P>
<UL>
<LI><P CLASS="LIST">Duplicating an entire sequence by copying into a new sequence</P></LI>
<LI><P CLASS="LIST">Creating sub-sequences of an existing sequence</P></LI>
<LI><P CLASS="LIST">Adding elements into a sequence</P></LI>
<LI><P CLASS="LIST">Copying a sequence from input or to output</P></LI>
<LI><P CLASS="LIST">Converting a sequence from one form into another</P></LI>
</UL>
<A NAME="idx263"><!></A>
<P>The uses of the copy algorithm are illustrated in the following sample program:</P>
<A NAME="idx268"><!></A>
<A NAME="idx267"><!></A>
<A NAME="idx266"><!></A>
<A NAME="idx265"><!></A>
<A NAME="idx264"><!></A>
<UL><PRE>
void copy_example()
// illustrates the use of the copy algorithm
// see alg1.cpp for complete source code
{
char *source = "reprise";
char *surpass = "surpass";
char buffer[120], *bufferp = buffer;
// example 1, a simple copy
std::copy(source, source + strlen(source) + 1, bufferp);
// example 2, self copies
std::copy(bufferp + 2, bufferp + strlen(buffer) + 1, bufferp);
int buflen = strlen(buffer) + 1;
std::copy_backward(bufferp, bufferp + buflen,
bufferp + buflen + 3);
std::copy(surpass, surpass + 3, bufferp);
// example 3, copy to output
std::copy(bufferp, bufferp + strlen(buffer),
std::ostream_iterator&lt;char,char&gt;(std::cout));
std::cout &lt;&lt; std::endl;
// example 4, use copy to convert type
std::list&lt;char&gt; char_list;
std::copy (bufferp, bufferp + strlen(buffer),
std::inserter(char_list, char_list.end()));
char *big = "big ";
std::copy(big, big + 4,
std::inserter(char_list, char_list.begin()));
char buffer2[120], *buffer2p = buffer2;
*std::copy(char_list.begin(), char_list.end(), buffer2p) = '\0';
std::cout &lt;&lt; buffer2 &lt;&lt; std::endl;
}
</PRE></UL>
<P>In example 1, the first call on <SAMP>std::copy()</SAMP> simply copies the string pointed to by the variable <SAMP>source</SAMP> into a buffer, resulting in the buffer containing the text <SAMP>"reprise"</SAMP>. Note that the ending position for the copy is one past the terminating null character, thus ensuring the null character is included in the copy operation.</P>
<P>The <SAMP>std::copy()</SAMP> operation is specifically designed to permit <I>self-copies</I>, which are copies of a sequence onto itself, as long as the destination <B><I><A HREF="../stdlibref/iterator.html">iterator</A></I></B> does not fall within the range formed by the source <B><I>iterator</I></B>s. This is illustrated by example 2. Here the copy begins at position 2 of the buffer and extends to the end, copying characters into the beginning of the buffer. This results in the buffer holding the value <SAMP>"prise"</SAMP>. </P>
<P>The second half of example 2 illustrates the use of the <SAMP>std::copy_backward()</SAMP> algorithm. This function performs the same task as the <SAMP>std::copy()</SAMP> algorithm, but moves elements from the end of the sequence first, progressing to the front of the sequence. If you think of the argument as a string, characters are moved starting from the right and progressing to the left. In this case the result is that <SAMP>buffer</SAMP> is assigned the value <SAMP>"priprise"</SAMP>. The first three characters are then modified by another <SAMP>std::copy()</SAMP> operation to the values <SAMP>"sur"</SAMP>, resulting in <SAMP>buffer</SAMP> holding the value<SAMP> "surprise"</SAMP>.</P>
<BLOCKQUOTE><HR><B>
NOTE -- In the copy_backwards algorithm, note that it is the order of transfer that is backwards, not the elements themselves; the relative placement of moved values in the target is the same as in the source.
</B><HR></BLOCKQUOTE>
<P>Example 3 illustrates <SAMP>std::copy()</SAMP> being used to move values to an output stream (see <A HREF="2-3.html#232">Section&nbsp;2.3.2</A>). The target in this case is an <SAMP>ostream_iterator</SAMP> generated for the output stream <SAMP>std::cout</SAMP>. A similar mechanism can be used for input values. For example, a simple mechanism to copy every word in the input stream into a <B><I><A HREF="../stdlibref/list.html">list</A></I></B> is the following call on <SAMP>copy()</SAMP>:</P>
<UL><PRE>
std::list&lt;std::string&gt; words;
std::istream_iterator&lt;std::string, char&gt; in_stream(std::cin), eof;
std::copy(in_stream, eof, std::inserter(words,
words.begin()));
</PRE></UL>
<P>This technique is used in the spell checking program described in <A HREF="8-3.html">Section&nbsp;8.3</A>.</P>
<A NAME="idx269"><!></A>
<P>Copy can also be used to convert from one type of stream to another. For example, the call in example 4 of the sample program copies the characters held in the buffer one by one into a <B><I><A HREF="../stdlibref/list.html">list</A></I></B> of characters. The call on <SAMP>std::inserter()</SAMP> creates an insert iterator, used to insert values into the <B><I>list</I></B>. The first call on <SAMP>std::copy()</SAMP> places the string <SAMP>surprise</SAMP>, created in example 2, into the <B><I>list</I></B>. The second call on <SAMP>std::copy()</SAMP> inserts the values from the string <SAMP>"big "</SAMP> onto the front of the <B><I>list</I></B>, resulting in the <B><I>list</I></B> containing the characters <SAMP>big surprise</SAMP>. The final call on <SAMP>std::copy()</SAMP> illustrates the reverse process, copying characters from a <B><I>list</I></B> back into a character buffer.</P>
<A NAME="1323"><H3>13.2.3 Initialize a Sequence with Generated Values</H3></A>
<A NAME="idx270"><!></A>
<P>A <I>generator</I> is a function that returns a series of values on successive invocations. Probably the generator you are most familiar with is a random number generator. However, generators can be constructed for a variety of different purposes, including initializing sequences.</P>
<A NAME="idx271"><!></A>
<P>Like <SAMP>std::fill()</SAMP> and <SAMP>std::fill_n()</SAMP>, the algorithms <SAMP>std::generate()</SAMP> and <SAMP>std::generate_n()</SAMP> are used to initialize or reinitialize a sequence. However, instead of a fixed argument, these algorithms draw their values from a generator. The declarations of these algorithms are as follows:</P>
<UL><PRE>
namespace std {
void generate(ForwardIterator, ForwardIterator, Generator);
void generate_n(OutputIterator, Size, Generator);
}
</PRE></UL>
<A NAME="idx272"><!></A>
<P>Our example program shows several uses of the generate algorithm to initialize a sequence:</P>
<A NAME="idx274"><!></A>
<A NAME="idx273"><!></A>
<UL><PRE>
string generateLabel () {
// generate a unique label string of the form L_ddd
// see alg1.cpp for complete source code
static int lastLabel = 0;
char labelBuffer[80];
std::ostrstream ost(labelBuffer, 80);
ost &lt;&lt; "L_" &lt;&lt; lastLabel++ &lt;&lt; '\0';
return std::string(labelBuffer);
}
void generate_example ()
// illustrate the use of the generate and generate_n algorithms
{
// example 1, generate a list of label values
std::list&lt;std::string&gt; labelList;
std::generate_n(std::inserter(labelList, labelList.begin()),
4, generateLabel);
// example 2, generate an arithmetic progression
std::vector&lt;int&gt; iVec(10);
std::generate(iVec.begin(), iVec.end(), iotaGen(2));
std::generate_n(iVec.begin(), 5, iotaGen(7));
}
}
</PRE></UL>
<A NAME="idx275"><!></A>
<P>A generator can be constructed as a simple function that <I>remembers</I> information about its previous history in one or more static variables. An example is shown in the beginning of the example program, where the function <SAMP>generateLabel()</SAMP> is described. This function creates a sequence of unique string labels, such as might be needed by a compiler. Each invocation on the function <SAMP>generateLabel()</SAMP> results in a new string of the form <SAMP>L_ddd</SAMP>, each with a unique digit value. Because the variable named <SAMP>lastLabel</SAMP> is declared as <SAMP>static</SAMP>, its value is remembered from one invocation to the next. The first example of the sample illustrates how this function might be used in combination with the <SAMP>std::generate_n()</SAMP> algorithm to initialize a list of four label values.</P>
<A NAME="idx276"><!></A>
<P>As we described in <A HREF="3.html">Chapter&nbsp;3</A>, a function is any object that will respond to the function call operator. Using this definition, classes can easily be constructed as functions. The class <B><I>iotaGen</I></B><I>,</I> is an example (see <A HREF="3-2.html">Section&nbsp;3.2</A>). The <B><I>iotaGen</I></B> function object creates a generator for an integer arithmetic sequence. In the second example in the sample program, this sequence is used to initialize a <B><I><A HREF="../stdlibref/vector.html">vector</A></I></B> with the integer values 2 through 11. A call on <SAMP>std::generate_n()</SAMP> is then used to overwrite the first 5 positions of the <B><I>vector</I></B> with the values 7 through 11, resulting in the <B><I>vector</I></B> <SAMP>7 8 9 10 11 7 8 9 10 11</SAMP>.</P>
<A NAME="1324"><H3>13.2.4 Swap Values from Two Parallel Ranges</H3></A>
<A NAME="idx277"><!></A>
<P>The template function <SAMP>std::swap()</SAMP> can be used to exchange the values of two objects of the same type. It has the following definition:</P>
<UL><PRE>
namespace std {
template &lt;class T&gt; void swap (T&amp; a, T&amp; b)
{
T temp(a);
a = b;
b = temp;
}
}
</PRE></UL>
<A NAME="idx278"><!></A>
<P>The function is generalized to <B><I><A HREF="../stdlibref/iterator.html">iterator</A></I></B>s in the function named <SAMP>std::iter_swap().</SAMP> The algorithm <SAMP>std::swap_ranges()</SAMP> extends this to entire sequences. The values denoted by the first sequence are exchanged with the values denoted by a second, parallel sequence. The description of the <SAMP>std::swap_ranges()</SAMP> algorithm is as follows:</P>
<UL><PRE>
namespace std {
ForwardIterator swap_ranges
(ForwardIterator first, ForwardIterator last,
ForwardIterator first2);
}
</PRE></UL>
<P>The second range is described only by a starting <B><I><A HREF="../stdlibref/iterator.html">iterator</A></I></B>. It is assumed but not verified that the second range has at least as many elements as the first range. </P>
<BLOCKQUOTE><HR><B>
NOTE -- A number of algorithms operate on two parallel sequences. In most cases, the second sequence is identified using only a starting iterator, not a starting and ending iterator pair. It is assumed, but never verified, that the second sequence is at least as large as the first. Errors will occur if this condition is not satisfied.
</B><HR></BLOCKQUOTE>
<P>In the example program, both <SAMP>std::swap()</SAMP> and <SAMP>std::iter_swap()</SAMP> are used separately and in combination:</P>
<A NAME="idx279"><!></A>
<UL><PRE>
void swap_example ()
// illustrates the use of the algorithm swap_ranges
// see alg1.cpp for complete source code
{
// first make two parallel sequences
int data[] = {12, 27, 14, 64}, *datap = data;
std::vector&lt;int&gt; aVec(4);
std::generate(aVec.begin(), aVec.end(), iotaGen(1));
// illustrate swap and iter_swap
std::swap(data[0], data[2]);
std::vector&lt;int&gt;::iterator last = aVec.end();
last--;
std::iter_swap(aVec.begin(), last);
// now swap the entire sequence
std::swap_ranges(aVec.begin(), aVec.end(), datap);
}
</PRE></UL>
<BR>
<HR>
<A HREF="13-1.html"><IMG SRC="images/bprev.gif" WIDTH=20 HEIGHT=21 ALT="Previous file" BORDER=O></A><A HREF="noframes.html"><IMG SRC="images/btop.gif" WIDTH=56 HEIGHT=21 ALT="Top of Document" BORDER=O></A><A HREF="booktoc.html"><IMG SRC="images/btoc.gif" WIDTH=56 HEIGHT=21 ALT="Contents" BORDER=O></A><A HREF="tindex.html"><IMG SRC="images/bindex.gif" WIDTH=56 HEIGHT=21 ALT="Index page" BORDER=O></A><A HREF="13-3.html"><IMG SRC="images/bnext.gif" WIDTH=20 HEIGHT=21 ALT="Next file" BORDER=O></A>
<!-- Google Analytics tracking code -->
<script src="http://www.google-analytics.com/urchin.js" type="text/javascript">
</script>
<script type="text/javascript">
_uacct = "UA-1775151-1";
urchinTracker();
</script>
<!-- end of Google Analytics tracking code -->
</BODY>
</HTML>