Download - 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)

Transcript
Page 1: 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)

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

Page 2: 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)

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?

Page 3: 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)

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?

Page 4: 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)

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;}

Page 5: 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)

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

Page 6: 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)

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

Page 7: 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)

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)

Page 8: 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)

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

Page 9: 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)

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

Page 10: 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)

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;

// ...

}

Page 11: 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)

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;

// ...

}

Page 12: 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)

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?

Page 13: 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)

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?

Page 14: 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)

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)

Page 15: 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)

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

Page 16: 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)

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

Page 17: 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)

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

Page 18: 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)

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

Page 19: 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)

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

Page 20: 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)

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)

Page 21: 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)

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(); } ... };

Page 22: 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)

CSE 332: C++ STL iterators

For Next Time

• Topic: C++ STL Algorithms

• Assigned Reading– pages 930-933

pages 1102-1128