CSE 332: C++ STL iterators What is an Iterator? An iterator must be able to do 2 main things...
-
Upload
jada-stukes -
Category
Documents
-
view
224 -
download
0
Transcript of CSE 332: C++ STL iterators What is an Iterator? An iterator must be able to do 2 main things...
CSE 332: C++ STL iterators
What is an Iterator?• An iterator must be able to do 2 main things
– Point to the start of a range of elements (in a container)– Give access the current element to which it points
• An iterator may be able to do 2 other important things – Move to point to the next element in a range– Be tested for having run through the entire range
• Intent (according to Gamma et al., “Design Patterns”)– Provide a way to access elements of a container
sequentially without exposing its underlying representation• Iterators help provide interface polymorphism
– Same interface, but different iterator implementations– Due to underlying containers’ different behaviors
• We’ll consider iterator interface methods above with– istream, ostream, array, linked list, bi-linked list
CSE 332: C++ STL iterators
STL Iterator Syntax and Semantics
• Pointers and integers are both Gamma et al. iteratorsfor (int * p = &A[0]; p – A < MAX; ++p) {
cout << *p << endl;
}
• Pointers (but not integers) are also STL iterators– Relies on associated types tricks we’ll cover later – Use traits based on typedef/struct/specialization
• The compiler can only check the syntax• Iterator definition must provide good semantics
– Including memory, aliasing, time complexity– Is it ok to implement p += n via a for loop? Why or why
not?
CSE 332: C++ STL iterators
Overview of STL Iterators• STL iterators generalize different uses of pointers
• Interface between algorithms and data structures– Algorithm manipulates iterators, not containers
• STL iterator “value” can be in one of 3 kinds of states:– Dereferenceable (points to a valid location in a range)– Past the end (points just past last valid location in a range)– Singular (points to nothing, like a zero pointer)
• STL iterators may be compared for equality• STL iterators may be copied and assigned • Why are STL iterators designed this way?
CSE 332: C++ STL iterators
Linear Search Example (Based on Austern)char* strchr(char* s, char c) { while (*s != ‘\0’ && *s != c) { ++s; } return s;}
• Not a very general solution – Only handles char (not wchar_t, uchar, etc.)– “Range” is up to but not including the ‘\0’
• Only applies to “zero terminated” strings
• First generalization: use a proper range– Provide an integer range length (how far to count)– Provide a first and last pointer into the array
char* find(char* start, char * end, char c) { while (start != end && *start != c) { ++start; } return start;}
CSE 332: C++ STL iterators
A Closer Look at Rangeschar* find(char* start, char * end, char c) { while (start != end && *start != c) { ++start; } return start;}
searches all positions in the string (from start up to but not including end) for a position with value c– A closed/open range: [start, end)
• A few questions about ranges to consider– At what position is ‘\0’ in “hello” ?– What is the last element in [0,1) ?
• Closed/open ranges help avoid off-by-one errors– The number of elements in the range [start, end) is end - start
CSE 332: C++ STL iterators
Some Definitions Related to Ranges• A valid range can be traversed safely with an iterator• An empty range [p,p) is valid• If [first, last) is valid and non-empty, then [first+1, last) is also valid– Proof: iterative induction on the range
• If[first, last) is valid – and position mid is reachable from first – and last is reachable from mid– then [first, mid) and [mid, last) are also valid
• If [first, mid) and [mid, last) are valid, then [first, last) is valid– Proof: divide and conquer induction on range
CSE 332: C++ STL iterators
Back to the Linear Search Example• Second generalization (we looked at this code before)template <typename Iterator, typename T>Iterator find2 (Iterator first, Iterator last,
const T & value) { while (first != last && *first != value) { ++first; } return first;}
• With both the iterator and value types being template type parameters, the function becomes very generic – Searches any one-dimensional sequence of elements– But, this raises some important issues about the iterator type
(especially about what other types are associated with it)
CSE 332: C++ STL iterators
An Important Technique: Traits• If we want to use iterators in templates, then we
need to provide additional info about them– Some information is fairly basic
• Type for expressing distance between iterators• Type obtained when an iterator is dereferenced
– Some information is more subtle and advanced• Whether or not an iterator can move backward, or be
moved an arbitrary distance in constant time
• Why do we need to provide this information?– For basic info, to write code that compiles– For advanced info, to influence compiler’s matching
• To do this across diverse types, we need traits
CSE 332: C++ STL iterators
Motivating Traits: Iterator’s Value Type• Why are traits needed? • See example to the left
– Illustrates problem of writing a generic swap function template
• First approach– Work around the
problem– Let compiler resolve the
value type– Define a forwarding
function– Defer implementation to
an internal function– Can we improve this?
// Austern, pp. 34: can’t write
// template <typename I>
// void swap (I i1, I i2){
// T tmp = *i1;
// *i1 = *i2;
// *i2 = tmp;
// }
template <typename I, typename T>
void swap_impl (I i1, I i2, T t){
T tmp = *i1;
*i1 = *i2;
*i2 = tmp;
}
template < typename I>
void swap (I i1, I i2)
{
swap_impl (i1, i2, *i2);
}
value type
CSE 332: C++ STL iterators
Iterator’s Value Type (continued)
• Second approach– Declare the value
type within a class– Algorithms can then
rely on that type in their concepts
– A step in the right direction, anyway
– What’s the limitation?
// Based on Austern, pp. 34
template <typename T>
class MyIterator {
public:
typedef T value_type;
// ...
private:
T * current_;
};
template <typename I>
void swap (I i1, I i2)
{
I::value_type temp;
// ...
}
CSE 332: C++ STL iterators
Iterator Traits
• Third approach: a partial solution– Type indirection – Via an iterator
traits class– Why do this?– Have we made
progress?
// Based on Austern, pp. 35
template <typename I>
struct iterator_traits {
typedef typename I::value_type value_type;
};
template <typename I>
void swap (I i1, I i2)
{
iterator_traits<I>::value_type temp;
// ...
}
CSE 332: C++ STL iterators
Iterator Traits (continued)
• Fourth approach: a complete solution– Different versions
of iterator_traits– Uses template
specialization– C++ compiler will
select the most specific match
// Based on Austern, pp. 35
template <typename I>
struct iterator_traits {
typedef typename I::value_type
value_type;
};
template <typename T>
struct iterator_traits<T*> {
typedef T value_type;
};
template <typename T>
struct iterator_traits<const T*> {
typedef T value_type; // a subtlety
};
Why do we need this one, too?
CSE 332: C++ STL iterators
More About Iterators Associated Types• Difference Type
– Type for “distance” between two iterators i1 and i2
– E.g., ptrdiff_t
• Reference, Value Types– For T *p, value type is T, *p
normally returns T &– For const T *p, value type is const
T, *p gives const T &
• Iterator Concept Category– Most refined concept it models– More about how this is used, when
we cover STL algorithms in detailhow far? units?
how far? units?
CSE 332: C++ STL iterators
Iterator Concept Hierarchy
Input Iterator Output Iterator
Forward Iterator
Bidirectional Iterator
Random Access Iterator
•value persists after read/write•values have locations•can express distance between two iterators
•read or write a value (one-shot)
Linked-list style access (slist)
Bi-linked-list style access
(list)Array/buffer style access
(vector, deque)
“destructive” read at head of stream
(istream)
“transient” write to stream (ostream)
CSE 332: C++ STL iterators
Input/Output Iterator Concepts & Models
• Important Input Iterator Concept Expressions*i (read value at the head of the stream)i->m (access member through iterator)++i, i++ (move the iterator to next element in stream)
• Some Models of the Input Iterator Conceptistream_iterator, most other STL iterators
• Important Output Iterator Concept ExpressionsX y(x), X y=x, y = x (copy construct / assign iterators)*x = t, (write value t into the stream) x++, ++x (move the iterator to next element in stream)
• Some Models of Output Iterator Conceptfront_insert_iteratorback_insert_iteratorostream_iterator
CSE 332: C++ STL iterators
Forward/Bidirectional Iterator Concepts & Models• Important Forward Iterator Concept Expressions
– Can pass same forward iterator in multiple arguments
X x, X(),(default construction)
++i, i++ (move from location to location)
*i (non-destructive access to container element)
• Some Models of the Forward Iterator Conceptslist<double>::const_iterator
hash_set<string>::iterator
• Bidireational Iterator Concept also requires--i, i-- (move from location back to earlier location)
• Some Models of the Bidirectional Iterator Conceptlist<int>::iterator, set<string>::iterator
CSE 332: C++ STL iterators
Random Access Iterator Concepts & Models• Important Random Access Iterator Concept
Expressionsi+=n, i-=n (moving iterator given distance in constant time)i+n, n+i, i-n, n-i, i-j, i<j (iterator arithmetic)i[n], i[n]=t (indexing a container using an iterator)– Thought Question: we can express the distance between
two Forward Iterators, so why don’t those iterators have i-j or i<j ?
• Some Models of the Random Access Iterator Conceptvector<int>::iteratordeque<int>::iteratorchar *
• Compiler must be able to determine to which category an iterator belongs– Allows it to match an iterator with
CSE 332: C++ STL iterators
Advice for Designing Your Own Iterators
• Use the iterator concept requirements as a checklist– Also good advice for writing containers and functors
• Make you support both constant and mutable objects• Define associated types appropriately
– More on this in the lecture on generic programming
• Provide as wide an iterator interface as possible without loss of efficiency
• Obey the aliasing rule we talked about with pointers– Two iterators equal if and only if they point to same variable
i == j &(*i) == &(*j)
*i == *j
CSE 332: C++ STL iterators
Advice for Using Iterators• Write a concept expression checklist for iterator
developers to use in designing their iterators
• Watch out for empty ranges
• Require as narrow an iterator interface as possible without loss of efficiency– Avoid over-constraining unnecessarily
– E.g., requiring just == and < vs. also > and !=
• Use selective dispatching techniques to provide both efficiency and generality
CSE 332: C++ STL iterators
Example of Using Iterators in the STL• From Austern, pp. 355• Copies values from an istream into a vector• What exactly is going on here?
int main () { vector<int> V; copy (istream_iterator<int> (cin), istream_iterator<int> (), back_inserter (V)); }
• (Thanks to Morgan Deters for this example)
CSE 332: C++ STL iterators
How the Iterator Works in this Example
• From the g++ 2.95.2 STL source code :
template <class _Tp, class _Dist = ptrdiff_t> class istream_iterator { ... public: istream_iterator() : _M_stream(&cin), _M_end_marker(false) {}
istream_iterator(istream& __s) : _M_stream(&__s) { _M_read(); } ... };
CSE 332: C++ STL iterators
For Next Time
• Topic: C++ STL Algorithms
• Assigned Reading– pages 930-933
pages 1102-1128