Iterators. McGraw-Hill The Complete Reference Fourth Edition
إعلان
إعلان
862
C + + : T h e C o m p l e t e R e f e r e n c e
T his chapter describes the classes and functions that support iterators, allocators, and function objects. These components are part of the standard template library.
They may also be used for other purposes.
Iterators
While containers and algorithms form the foundation of the standard template library, iterators are the glue that holds it together. An iterator is a generalization (or perhaps more precisely, an abstraction) of a pointer. Iterators are handled in your program like pointers, and they implement the standard pointer operators. They give you the ability to cycle through the contents of a container in much the same way that you would use a pointer to cycle through an array.
Standard C++ defines a set of classes and functions that support iterators. However, for the vast majority of STL-based programming tasks, you will not use these classes directly. Instead, you will use the iterators provided by the various containers in the
STL, manipulating them like you would any other pointer. The preceding notwithstanding, it is still valuable to have a general understanding of the iterator classes and their contents.
For example, it is possible to create your own iterators that accommodate special situations. Also, developers of third-party libraries will find the iterator classes useful.
Iterators use the header <iterator>.
The Basic Iterator Types
There are five types of iterators:
Iterator
Random Access
Bidirectional
Forward
Input
Output
Access Allowed
Store and retrieve values. Elements may be accessed randomly.
Store and retrieve values. Forward and backward moving.
Store and retrieve values. Forward moving only.
Retrieve but not store values. Forward moving only.
Store but not retrieve values. Forward moving only.
In general, an iterator that has greater access capabilities can be used in place of one that has lesser capabilities. For example, a forward iterator can be used in place of an input iterator.
The STL also supports reverse iterators. Reverse iterators are either bidirectional or random-access iterators that move through a sequence in the reverse direction. Thus, if
C h a p t e r 3 5 : S T L I t e r a t o r s , A l l o c a t o r s , a n d F u n c t i o n O b j e c t s
863 a reverse iterator points to the end of a sequence, incrementing that iterator will cause it to point one element before the end.
Stream-based iterators are available that allow you to operate on streams through iterators. Finally, insert iterator classes are provided that simplify the insertion of elements into a container.
All iterators must support the pointer operations allowed by their type. For example, an input iterator class must support –>, ++, *, ==, and !=. Further, the * operator cannot be used to assign a value. By contrast, a random-access iterator must support –>, +, ++, –, , *,
<
, >, <=, >=, –=, +=, ==, !=, and [ ]. Also, the * must allow assignment.
The Low-Level Iterator Classes
The <iterator> header defines several classes that provide support for and aid in the implementation of iterators. As explained in Chapter 24, each of the STL containers defines its own iterator type, which is typedefed as iterator. Thus, when using the standard
STL containers, you will not usually interact directly with the low-level iterator classes themselves. But you can use the classes described here to derive your own iterators.
Several of the iterator classes make use of the ptrdiff_t type. This type is capable of representing the difference between two pointers.
iterator
The iterator class is a base for iterators. It is shown here: template <class Cat, class T, class Dist = ptrdiff_t, class Pointer = T *, class Ref = T &> struct iterator { typedef T value_type;
}; typedef Dist difference_type; typedef Pointer pointer; typedef Ref reference; typedef Cat iterator_category;
Here, difference_type is a type that can hold the difference between two addresses,
value_type
is the type of value operated upon, pointer is the type of a pointer to a value, reference is the type of a reference to a value, and iterator_category describes the type of the iterator (such as input, random-access, etc.).
The following category classes are provided.
struct input_iterator_tag {}; struct output_iterator_tag {};
864
C + + : T h e C o m p l e t e R e f e r e n c e struct forward_iterator_tag: public input_iterator_tag {}; struct bidirectional_iterator_tag: public forward_iterator_tag {}; struct random_access_iterator_tag: public bidirectional_iterator_tag {};
iterator_traits
The class iterator_traits provides a convenient means of exposing the various types defined by an iterator. It is defined like this: template<class Iterator> struct iterator_traits { typedef Iterator::difference_type difference_type; typedef Iterator::value_type value_type; typedef Iterator::pointer pointer; typedef Iterator::reference reference; typedef Iterator::iterator_category iterator_category;
}
The Predefined Iterators
The <iterator> header contains several predefined iterators that may be used directly by your program or to help create other iterators. These iterators are shown in Table 35-1.
Notice that there are four iterators that operate on streams. The main purpose for the stream iterators is to allow streams to be manipulated by algorithms. Also notice the insert iterators. When these iterators are used in an assignment statement, they insert elements into a sequence rather than overwriting existing elements.
Each of the predefined iterators is examined here.
insert_iterator
The insert_iterator class supports output iterators that insert objects into a container. Its template definition is shown here: template <class Cont> class insert_iterator: public iterator<output_iterator_tag, void, void, void, void>
Here, Cont is the type of container that the iterator operates upon. insert_iterator has the following constructor: insert_iterator(Cont &cnt, typename Cont::iterator itr);
Here, cnt is the container being operated upon and itr is an iterator into the container that will be used to initialize the insert_iterator.
C h a p t e r 3 5 : S T L I t e r a t o r s , A l l o c a t o r s , a n d F u n c t i o n O b j e c t s
865
Class insert_iterator back_insert_iterator front_insert_iterator reverse_iterator istream_iterator istreambuf_iterator ostream_iterator ostreambuf_iterator
Description
An output iterator that inserts anywhere in the container.
An output iterator that inserts at the end of a container.
An output iterator that inserts at the front of a container.
A reverse, bidirectional, or random-access iterator.
An input stream iterator.
An input streambuf iterator.
An output stream iterator.
An output streambuf iterator.
Table 35-1.
The Predefined Iterator Classes
insert_iterator
defines the following operators: =, *, ++. A pointer to the container is stored in a protected variable called container. The container's iterator is stored in a protected variable called iter.
Also defined is the function inserter( ), which creates an insert_iterator. It is shown here: template <class Cont, class Iterator> insert_iterator<Cont> inserter(Cont &cnt, Iterator itr);
Insert iterators insert into, rather than overwrite, the contents of a container. To fully understand the effects of an insert iterator, consider the following program. It first creates a small vector of integers, and then uses an insert_iterator to insert new elements into the vector rather than overwriting existing elements.
// Demonstrate insert_iterator.
#include <iostream>
#include <iterator>
#include <vector> using namespace std; int main()
{ vector<int> v;
866
C + + : T h e C o m p l e t e R e f e r e n c e vector<int>::iterator itr; int i; for(i=0; i<5; i++) v.push_back(i); cout << "Original array: "; itr = v.begin(); while(itr != v.end()) cout << *itr++ << " "; cout << endl; itr = v.begin(); itr += 2; // point to element 2
// create insert_iterator to element 2 insert_iterator<vector<int> > i_itr(v, itr);
// insert rather than overwrite
*i_itr++ = 100;
*i_itr++ = 200; cout << "Array after insertion: "; itr = v.begin(); while(itr != v.end()) cout << *itr++ << " ";
} return 0;
The output from the program is shown here:
Original array: 0 1 2 3 4
Array after insertion: 0 1 100 200 2 3 4
In the program, had the assignments of 100 and 200 been done using a standard iterator, the original elements in the array would have been overwritten. The same basic process applies to back_insert_iterator and front_insert_iterator as well.
C h a p t e r 3 5 : S T L I t e r a t o r s , A l l o c a t o r s , a n d F u n c t i o n O b j e c t s
867
back_insert_iterator
The back_insert_iterator class supports output iterators that insert objects on the end of a container using push_back( ). Its template definition is shown here: template <class Cont> class back_insert_iterator: public iterator<output_iterator_tag, void, void, void, void>
Here, Cont is the type of container that the iterator operates upon. back_insert_iterator has the following constructor: explicit back_insert_iterator(Cont &cnt);
Here, cnt is the container being operated upon. All insertions will occur at the end.
back_insert_iterator
defines the following operators: =, *, ++. A pointer to the container is stored in a protected variable called container.
Also defined is the function back_inserter( ), which creates a back_insert_iterator.
It is shown here: template <class Cont> back_insert_iterator<Cont> back_inserter(Cont &cnt);
front_insert_iterator
The front_insert_iterator class supports output iterators that insert objects on the front of a container using push_front( ). Its template definition is shown here: template <class Cont> class front_insert_iterator: public iterator<output_iterator_tag, void, void, void, void>
Here, Cont is the type of container that the iterator operates upon. front_insert_iterator has the following constructor: explicit front_insert_iterator(Cont &cnt);
Here, cnt is the container being operated upon. All insertions will occur at the front.
front_insert_iterator
defines the following operators: =, *, ++. A pointer to the container is stored in a protected variable called container.
Also defined is the function front_inserter( ), which creates a front_insert_iterator.
It is shown here: template <class Cont> front_insert_iterator<Cont> inserter(Cont &cnt);
868
C + + : T h e C o m p l e t e R e f e r e n c e
reverse_iterator
The reverse_iterator class supports reverse iterator operations. A reverse iterator operates the opposite of a normal iterator. For example, ++ causes a reverse iterator to back up.
Its template definition is shown here: template <class Iter> class reverse_iterator: public iterator<iterator_traits<Iter>::iterator_category, iterator_traits<Iter>::value_type, iterator_traits<Iter>::difference_type, iterator_traits<Iter>::pointer, iterator_traits<Iter>::reference>
Here, Iter is either a random-access iterator or a bidirectional iterator. reverse_iterator has the following constructors: reverse_iterator( ); explicit reverse_iterator(Iter itr);
Here, itr is an iterator that specifies the starting location.
If Iter is a random-access iterator, then the following operators are available: –>, +,
++
, –, – –, *, <, >, <=, >=, –=, +=, ==, !=, and [ ] . If Iter is a bidirectional iterator, then only –>, ++, – –, *, ==, and != are available.
The reverse_iterator class defines a protected member called current, which is an iterator to the current location.
The function base( ) is also defined by reverse_iterator. Its prototype is shown here:
Iter base( ) const;
It returns an iterator to the current location.
istream_iterator
The istream_iterator class supports input iterator operations on a stream. Its template definition is shown here: template <class T, class CharType, class Attr = char_traits<CharType>, class Dist = ptrdiff_t> class istream_iterator: public iterator<input_iterator_tag, T, Dist, const T *, const T &>
Here, T is the type of data being transferred, and CharType is the character type (char or
wchar_t
) that the stream is operating upon. Dist is a type capable of holding the difference between two addresses. istream_iterator has the following constructors:
C h a p t e r 3 5 : S T L I t e r a t o r s , A l l o c a t o r s , a n d F u n c t i o n O b j e c t s
869 istream_iterator( ); istream_iterator(istream_type &stream); istream_iterator(const istream_iterator<T, CharType, Attr, Dist> &ob);
The first constructor creates an iterator to an empty stream. The second creates an iterator to the stream specified by stream. The type istream_type is a typedef that specifies the type of the input stream. The third form creates a copy of an istream_iterator object.
The istream_iterator class defines the following operators: –>, *, ++. The operators
==
and != are also defined for objects of type istream_iterator.
Here is a short program that demonstrates istream_iterator. It reads and displays characters from cin until a period is received.
// Use istream_iterator
#include <iostream>
#include <iterator> using namespace std; int main()
{ istream_iterator<char> in_it(cin); do { cout << *in_it++;
} while (*in_it != '.');
} return 0;
istreambuf_iterator
The istreambuf_iterator class supports character input iterator operations on a stream.
Its template definition is shown here: template <class CharType, class Attr = char_traits<CharType> > class istreambuf_iterator: public iterator<input_iterator_tag, CharType, typename Attr::off_type,
CharType *, CharType &>
Here, CharType is the character type (char or wchar_t) that the stream is operating upon.
istreambuf_iterator
has the following constructors: istreambuf_iterator( ) throw( ); istreambuf_iterator(istream_type &stream) throw( ); istreambuf_iterator(streambuf_type *streambuf) throw( );
870
C + + : T h e C o m p l e t e R e f e r e n c e
The first constructor creates an iterator to an empty stream. The second creates an iterator to the stream specified by stream. The type istream_type is a typedef that specifies the type of the input stream. The third form creates an iterator using the stream buffer specified by streambuf.
The istreambuf_iterator class defines the following operators: *, ++. The operators
==
and != are also defined for objects of type istreambuf_iterator.
istreambuf_iterator
defines the member function equal( ), which is shown here: bool equal(istreambuf_iterator<CharType, Attr> &ob);
Its operation is a bit counterintuitive. It returns true if the invoking iterator and ob both point to the end of the stream. It also returns true if both iterators do not point to the end of the stream. There is no requirement that what they point to be the same. It returns
false
otherwise. The == and != operators work in the same fashion.
ostream_iterator
The ostream_iterator class supports output iterator operations on a stream. Its template definition is shown here: template <class T, class CharType, class Attr = char_traits<CharType> > class ostream_iterator: public iterator<output_iterator_tag, void, void, void, void>
Here, T is the type of data being transferred, CharType is the character type (char or
wchar_t
) that the stream is operating upon. ostream_iterator has the following constructors: ostream_iterator(ostream_type &stream); ostream_iterator(ostream_type &stream, const CharType *delim); ostream_iterator(const ostream_iterator<T, CharType, Attr> &ob);
The first creates an iterator to the stream specified by stream. The type ostream_type is a typedef that specifies the type of the output stream. The second form creates an iterator to the stream specified by stream and uses the delimiters specified by delim. The delimiters are written to the stream after every output operation. The third form creates a copy of an ostream_iterator object.
The ostream_iterator class defines the following operators: =, *, ++.
Here is a short program that demonstrates ostream_iterator.
C h a p t e r 3 5 : S T L I t e r a t o r s , A l l o c a t o r s , a n d F u n c t i o n O b j e c t s
871
// Use ostream_iterator
#include <iostream>
#include <iterator> using namespace std; int main()
{ ostream_iterator<char> out_it(cout);
*out_it = 'X'; out_it++;
*out_it = 'Y'; out_it++;
*out_it = ' '; char str[] = "C++ Iterators are powerful.\n"; char *p = str; while(*p) *out_it++ = *p++; ostream_iterator<double> out_double_it(cout);
*out_double_it = 187.23; out_double_it++;
*out_double_it = -102.7;
} return 0;
The output from this program is shown here:
XY C++ Iterators are powerful.
187.23-102.7
ostreambuf_iterator
The ostreambuf_iterator class supports character output iterator operations on a stream.
Its template definition is shown here: template <class CharType, class Attr = char_traits<CharType> > class ostreambuf_iterator: public iterator<output_iterator_tag, void, void, void, void>
تنزيل
إعلان