462b73969e
2001-05-30 Phil Edwards <pme@sources.redhat.com> * docs/doxygen/user.cfg.in: Minor addition. * docs/html/documentation.html: Reorganize. Put most-looked-at stuff first. * docs/html/install.html: Update for 3.0. HTML fixups. * docs/html/17_intro/howto.html: Likewise. * docs/html/18_support/howto.html: Likewise. * docs/html/19_diagnostics/howto.html: Likewise. * docs/html/20_util/howto.html: Likewise. * docs/html/23_containers/howto.html: Likewise. * docs/html/24_iterators/howto.html: Likewise. More notes. * docs/html/25_algorithms/howto.html: Likewise. * docs/html/26_numerics/howto.html: Likewise. More notes. * docs/html/27_io/howto.html: Likewise. * docs/html/ext/howto.html: Likewise. * docs/html/faq/index.html: Likewise. * docs/html/faq/index.txt: Regenerate. * docs/html/27_io/iostreams_hierarchy.pdf: Remove in favor of Doxygen-created documentation. From-SVN: r42723
185 lines
8.0 KiB
HTML
185 lines
8.0 KiB
HTML
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN">
|
|
<HTML>
|
|
<HEAD>
|
|
<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
|
|
<META NAME="AUTHOR" CONTENT="pme@sources.redhat.com (Phil Edwards)">
|
|
<META NAME="KEYWORDS" CONTENT="HOWTO, libstdc++, GCC, g++, libg++, STL">
|
|
<META NAME="DESCRIPTION" CONTENT="HOWTO for the libstdc++ chapter 24.">
|
|
<META NAME="GENERATOR" CONTENT="vi and eight fingers">
|
|
<TITLE>libstdc++-v3 HOWTO: Chapter 24</TITLE>
|
|
<LINK REL=StyleSheet HREF="../lib3styles.css">
|
|
<!-- $Id: howto.html,v 1.2 2001/04/03 00:26:56 pme Exp $ -->
|
|
</HEAD>
|
|
<BODY>
|
|
|
|
<H1 CLASS="centered"><A NAME="top">Chapter 24: Iterators</A></H1>
|
|
|
|
<P>Chapter 24 deals with the FORTRAN subroutines for automatically
|
|
transforming lemmings into gold.
|
|
</P>
|
|
|
|
|
|
<!-- ####################################################### -->
|
|
<HR>
|
|
<H1>Contents</H1>
|
|
<UL>
|
|
<LI><A HREF="#1">They ain't pointers!</A>
|
|
<LI><A HREF="#2">It ends <EM>where?</EM></A>
|
|
</UL>
|
|
|
|
<HR>
|
|
|
|
<!-- ####################################################### -->
|
|
|
|
<H2><A NAME="1">They ain't pointers!</A></H2>
|
|
<P><A HREF="../faq/index.html#5_1">FAQ 5.1</A> points out that iterators
|
|
are not implemented as pointers. They are a generalization of
|
|
pointers, but they are implemented in libstdc++-v3 as separate classes.
|
|
</P>
|
|
<P>Keeping that simple fact in mind as you design your code will
|
|
prevent a whole lot of difficult-to-understand bugs.
|
|
</P>
|
|
<P>You can think of it the other way 'round, even. Since iterators
|
|
are a generalization, that means that <EM>pointers</EM> are
|
|
<EM>iterators</EM>, and that pointers can be used whenever an
|
|
iterator would be. All those functions in the Algorithms chapter
|
|
of the Standard will work just as well on plain arrays and their
|
|
pointers.
|
|
</P>
|
|
<P>That doesn't mean that when you pass in a pointer, it gets wrapped
|
|
into some special delegating iterator-to-pointer class with a layer
|
|
of overhead. (If you think that's the case anywhere, you don't
|
|
understand templates to begin with...) Oh, no; if you pass
|
|
in a pointer, then the compiler will instantiate that template
|
|
using T* as a type and good old high-speed pointer arithmetic as
|
|
its operations, so the resulting code will be doing exactly the same
|
|
things as it would be doing if you had hand-coded it yourself (for
|
|
the 273rd time).
|
|
</P>
|
|
<P>How much overhead <EM>is</EM> there when using an interator class?
|
|
Very little. Most of the layering classes contain nothing but
|
|
typedefs, and typedefs are "meta-information" that simply
|
|
tell the compiler some nicknames; they don't create code. That
|
|
information gets passed down through inheritance, so while the
|
|
compiler has to do work looking up all the names, your runtime code
|
|
does not. (This has been a prime concern from the beginning.)
|
|
</P>
|
|
<P>Return <A HREF="#top">to top of page</A> or
|
|
<A HREF="../faq/index.html">to the FAQ</A>.
|
|
</P>
|
|
|
|
<HR>
|
|
<H2><A NAME="2">It ends <EM>where?</EM></A></H2>
|
|
<P>This starts off sounding complicated, but is actually very easy,
|
|
especially towards the end. Trust me.
|
|
</P>
|
|
<P>Beginners usually have a little trouble understand the whole
|
|
'past-the-end' thing, until they remember their early algebra classes
|
|
(see, they </EM>told</EM> you that stuff would come in handy!) and
|
|
the concept of half-open ranges.
|
|
</P>
|
|
<P>First, some history, and a reminder of some of the funkier rules in
|
|
C and C++ for builtin arrays. The following rules have always been
|
|
true for both languages:
|
|
<OL>
|
|
<LI>You can point anywhere in the array, <EM>or to the first element
|
|
past the end of the array</EM>. A pointer that points to one
|
|
past the end of the array is guaranteed to be as unique as a
|
|
pointer to somewhere inside the array, so that you can compare
|
|
such pointers safely.
|
|
<LI>You can only dereference a pointer that points into an array.
|
|
If your array pointer points outside the array -- even to just
|
|
one past the end -- and you dereference it, Bad Things happen.
|
|
<LI>Strictly speaking, simply pointing anywhere else invokes
|
|
undefined behavior. Most programs won't puke until such a
|
|
pointer is actually dereferenced, but the standards leave that
|
|
up to the platform.
|
|
</OL>
|
|
The reason this past-the-end addressing was allowed is to make it
|
|
easy to write a loop to go over an entire array, e.g.,
|
|
while (*d++ = *s++);.
|
|
</P>
|
|
<P>So, when you think of two pointers delimiting an array, don't think
|
|
of them as indexing 0 through n-1. Think of them as <EM>boundary
|
|
markers</EM>:
|
|
<PRE>
|
|
|
|
beginning end
|
|
| |
|
|
| | This is bad. Always having to
|
|
| | remember to add or subtract one.
|
|
| | Off-by-one bugs very common here.
|
|
V V
|
|
array of N elements
|
|
|---|---|--...--|---|---|
|
|
| 0 | 1 | ... |N-2|N-1|
|
|
|---|---|--...--|---|---|
|
|
|
|
^ ^
|
|
| |
|
|
| | This is good. This is safe. This
|
|
| | is guaranteed to work. Just don't
|
|
| | dereference 'end'.
|
|
beginning end
|
|
|
|
</PRE>
|
|
See? Everything between the boundary markers is part of the array.
|
|
Simple.
|
|
</P>
|
|
<P>Now think back to your junior-high school algebra course, when you
|
|
were learning how to draw graphs. Remember that a graph terminating
|
|
with a solid dot meant, "Everything up through this point,"
|
|
and a graph terminating with an open dot meant, "Everything up
|
|
to, but not including, this point," respectively called closed
|
|
and open ranges? Remember how closed ranges were written with
|
|
brackets, <EM>[a,b]</EM>, and open ranges were written with parentheses,
|
|
<EM>(a,b)</EM>?
|
|
</P>
|
|
<P>The boundary markers for arrays describe a <EM>half-open range</EM>,
|
|
starting with (and including) the first element, and ending with (but
|
|
not including) the last element: <EM>[beginning,end)</EM>. See, I
|
|
told you it would be simple in the end.
|
|
</P>
|
|
<P>Iterators, and everything working with iterators, follows this same
|
|
time-honored tradition. A container's <TT>begin()</TT> method returns
|
|
an iterator referring to the first element, and its <TT>end()</TT>
|
|
method returns a past-the-end iterator, which is guaranteed to be
|
|
unique and comparable against any other iterator pointing into the
|
|
middle of the container.
|
|
</P>
|
|
<P>Container constructors, container methods, and algorithms, all take
|
|
pairs of iterators describing a range of values on which to operate.
|
|
All of these ranges are half-open ranges, so you pass the beginning
|
|
iterator as the starting parameter, and the one-past-the-end iterator
|
|
as the finishing parameter.
|
|
</P>
|
|
<P>This generalizes very well. You can operate on sub-ranges quite
|
|
easily this way; functions accepting a <EM>[first,last)</EM> range
|
|
don't know or care whether they are the boundaries of an entire {array,
|
|
sequence, container, whatever}, or whether they only enclose a few
|
|
elements from the center. This approach also makes zero-length
|
|
sequences very simple to recognize: if the two endpoints compare
|
|
equal, then the {array, sequence, container, whatever} is empty.
|
|
</P>
|
|
<P>Just don't dereference <TT>end()</TT>.
|
|
</P>
|
|
<P>Return <A HREF="#top">to top of page</A> or
|
|
<A HREF="../faq/index.html">to the FAQ</A>.
|
|
</P>
|
|
|
|
|
|
|
|
|
|
<!-- ####################################################### -->
|
|
|
|
<HR>
|
|
<P CLASS="fineprint"><EM>
|
|
Comments and suggestions are welcome, and may be sent to
|
|
<A HREF="mailto:libstdc++@gcc.gnu.org">the mailing list</A>.
|
|
<BR> $Id: howto.html,v 1.2 2001/04/03 00:26:56 pme Exp $
|
|
</EM></P>
|
|
|
|
|
|
</BODY>
|
|
</HTML>
|