Agenda The concept of an iterator Iterator concepts

  • Slides: 37
Download presentation
Agenda �The concept of an “iterator” �Iterator concepts hierarchy �Itarotrs and containers �Iterators and

Agenda �The concept of an “iterator” �Iterator concepts hierarchy �Itarotrs and containers �Iterators and algorithms �Iterators validity �Containers adaptors

Stl iterators

Stl iterators

The iterator concept �A generalization of a pointer. �An objects that gives access to

The iterator concept �A generalization of a pointer. �An objects that gives access to elements of another object. �The iterator concept is the set of all the operations it can perform on the referenced object. �The iterator required operations are derived from the nature of the referenced object.

Iterator concepts hierarchy

Iterator concepts hierarchy

Iterator operations �Output: write only and can write only once �Input: read many times

Iterator operations �Output: write only and can write only once �Input: read many times each item �Forward supports both read and write �Bi-directional support also decrement �Random supports random access (just like C pointer)

Iterators & Containers �Bidirectional iterators for: �list, map, set �Random access iterators for: �Vector,

Iterators & Containers �Bidirectional iterators for: �list, map, set �Random access iterators for: �Vector, array �Input/output/forward iterators for: �iostreams (not a container)

Iterators and Containers • Each container defines an itertor type, and begin() and end()

Iterators and Containers • Each container defines an itertor type, and begin() and end() functions that return iterators. class Name. Of. Container { . . . typedef … iterator; // iterator type of Name. Of. Container iterator begin(); // first element of Name. Of. Container iterator end(); // element after last of Name. Of. Container

Iterator basic usage �With templates: Name. Of. Container<. . . > c . .

Iterator basic usage �With templates: Name. Of. Container<. . . > c . . . Name. Of. Container<. . . >: : iterator i; for(i= c. begin(); i!=c. end(); ++i) // do something that changes *i

const_iterators & Containers class Name. Of. Container { . . . typedef … const_iterator;

const_iterators & Containers class Name. Of. Container { . . . typedef … const_iterator; // iterator type of Name. Of. Container const_iterator begin() const; // first element const_iterator end() const; // element after last Name. Of. Container<. . . > c Name. Of. Container<. . . >: : const_iterator it; for( it= c. begin(); it!=c. end(); ++it) // do something that does not changes *it

Const iterators. . . iterator begin(); iterator end(); . . . const_iterator begin() const;

Const iterators. . . iterator begin(); iterator end(); . . . const_iterator begin() const; const_iterator end() const; �Note that the begin() and end() methods that return regular iterator are not const methods. i. e: if we get a container by const reference we can't use these methods, we have to use the methods that return const_iterator.

Iterator associated types � An iterator has associated types, for example its value type

Iterator associated types � An iterator has associated types, for example its value type (the type that its operator* returns). � Generic algorithms often need access to the iterator associated types. template <class Iterator> //this is an example. Not the real stl swap algorithm void iter_swap (Iterator a, Iterator b) { value_type tmp = *a; //How do we know the value type? *a = *b; *b = tmp; }

Iterator associated types �The associated types can be defined in a base iterator class

Iterator associated types �The associated types can be defined in a base iterator class (not good for a pointer). New iterators will derive from that class. �The associated types can be defined in an helper iterator traits class (good also for pointers).

Iterator base class template <class Category, class T, class Distance = ptrdiff_t, class Pointer

Iterator base class template <class Category, class T, class Distance = ptrdiff_t, class Pointer = T*, class Reference = T&> struct iterator { typedef T value_type; typedef Distance difference_type; typedef Pointer pointer; typedef Reference reference; typedef Category iterator_category; };

Iterator traits template <class Iterator> struct iterator_traits { typedef typename Iterator: : iterator_category; typedef

Iterator traits template <class Iterator> struct iterator_traits { typedef typename Iterator: : iterator_category; typedef typename Iterator: : value_type; typedef typename Iterator: : difference_type; typedef typename Iterator: : pointer; typedef typename Iterator: : reference; }; template <class T> struct iterator_traits<T*> //specialization for a pointer template argument { typedef random_access_iterator_tag iterator_category; typedef T value_type; typedef ptrdiff_t difference_type; typedef T* pointer; typedef T& reference; };

Iterator types usage template <class My. Iterator> void iter_swap (My. Iterator a, My. Iterator

Iterator types usage template <class My. Iterator> void iter_swap (My. Iterator a, My. Iterator b) { typedef typename My. Iterator : : value_type; value_type tmp = *a; *a = *b; *b = tmp; } template <class My. Iterator> void iter_swap (My. Iterator a, My. Iterator b) { typedef typename iterator_traits<My. Iterator>: : value_type; value_type tmp = *a; *a = *b; *b = tmp; }

Iterators & Sequence Containers Seq. Container. Name<. . . > c; first, last are

Iterators & Sequence Containers Seq. Container. Name<. . . > c; first, last are Seq. Container. Name<. . . >: : iterator i, j; any type of input iterator c. insert(i, x) // insert x before i c. insert(i, first, last) // insert elements in [first, last) before i c. erase(i) // erase element i points to c. erase(i, j) // erase elements in range [i, j)

Iterators & other Containers �insert and erase has the same ideas for different containers,

Iterators & other Containers �insert and erase has the same ideas for different containers, except they keep the invariants of the specific container. �For example, a Sorted Associative Container will remain sorted after insertions and erases.

Iterators and Assoc. Containers �For example - what does c. insert(pos, x) does, when

Iterators and Assoc. Containers �For example - what does c. insert(pos, x) does, when c is a Unique Sorted Associative Container? �Inserts x into the set, using pos as a hint to where it will be inserted: hint regarding the place to start searching for the correct point of insertion. �If the hint is good, will reduce the insertion time from O(log(N)) to O(1)

Iterators and Assoc. Containers Additional set of operations: � iterator c: : find(key_type const&

Iterators and Assoc. Containers Additional set of operations: � iterator c: : find(key_type const& key) Returns iterator to first element with key � iterator c: : lower_bound(key_type const& key) Returns iterator to first element greater or equal to key � iterator c: : upper_bound(key_type const& key) Returns iterator to first element greater than key � end() if not found

Iterators & Map �Suppose we work with: map<string, int> dictionary; map<string, int>: : iterator

Iterators & Map �Suppose we work with: map<string, int> dictionary; map<string, int>: : iterator i; i = dictionary. begin(); �What is the type of *i ? �map<string, int>: : value_type

Iterators & Map �Ok – but what is it? map<Key. Type, Value. Type> keeps

Iterators & Map �Ok – but what is it? map<Key. Type, Value. Type> keeps pairs: Key. Type key – “key” of entry Value. Type value – “value” of entry

pairs template< typename T 1, typename T 2> struct pair { typedef T 1

pairs template< typename T 1, typename T 2> struct pair { typedef T 1 first_type; typedef T 2 second_type; first_type first; second_type second; pair(const T 1& x, const T 2& y) : first(x), second(y) {} };

Map value_type template<typename Key, typename T, typename Cmp = less<Key>> class map { public:

Map value_type template<typename Key, typename T, typename Cmp = less<Key>> class map { public: typedef pair<const Key, T> value_type; typedef Key key_type; typedef T mapped_type; typedef Cmp key_compare; };

Using map iterator map<string, int> dict; . . . map<string, int>: : iterator i;

Using map iterator map<string, int> dict; . . . map<string, int>: : iterator i; for( i = dict. begin(); i != dict. end(); i++ ) { cout << i->first << " " << i->second << "n"; }

Iterators and algorithms �Stl algorithms operate on iterators, not on containers. �The algorithm will

Iterators and algorithms �Stl algorithms operate on iterators, not on containers. �The algorithm will work on any container, as long as the container iterator model the iterator concept required by the algorithm. �A container interface includes the strongest iterator it provides. �An algorithm interface includes the weakest iterator it requires.

Algorithm that requires an input iterator template<class Input. Iterator, class T> Input. Iterator find

Algorithm that requires an input iterator template<class Input. Iterator, class T> Input. Iterator find ( Input. Iterator first, Input. Iterator last, const T& value ) { for ( ; first!=last; first++) { if ( *first==value ) break; } return first; }

Algorithm that requires a forward iterator template<class Forward. Iterator 1, class Forward. Iterator 2>

Algorithm that requires a forward iterator template<class Forward. Iterator 1, class Forward. Iterator 2> Forward. Iterator 1 search ( Forward. Iterator 1 first 1, Forward. Iterator 1 last 1, Forward. Iterator 2 first 2, Forward. Iterator 2 last 2) { if (first 2==last 2) return first 1; while (first 1!=last 1) { Forward. Iterator 1 it 1 = first 1; Forward. Iterator 2 it 2 = first 2; while (*it 1==*it 2){ ++it 1; ++it 2; if (it 2==last 2) return first 1; if (it 1==last 1) return last 1; } ++first 1; } return last 1; }

Algorithm that requires random access iterator template <class Random. Access. Iterator, class Random. Number.

Algorithm that requires random access iterator template <class Random. Access. Iterator, class Random. Number. Generator> void random_shuffle ( Random. Access. Iterator first, Random. Access. Iterator last, Random. Number. Generator& rand ) { iterator_traits<Random. Access. Iterator>: : difference_type i, n; n = (last-first); for (i=n-1; i>0; --i) { swap (first[i], first[rand(i+1)]); } }

Iterators’ Validity �When working with iterators, we have to remember that their validity can

Iterators’ Validity �When working with iterators, we have to remember that their validity can be changed �What’s wrong with this code? Container c; Container: : iterator i; for(i=c. begin(); i!=c. end(); ++i) if(f(*i)) // f is some test { c. erase(i); } �Invalidates i, thus we cannot “++” it

Iterators’ Validity Two cases: �list, set, map �i is not a legal iterator �vector

Iterators’ Validity Two cases: �list, set, map �i is not a legal iterator �vector �i (might) point to the element after �In either case, this is not what we want…

Iterator validity – second try. . . Container c; Container: : iterator i= c.

Iterator validity – second try. . . Container c; Container: : iterator i= c. begin(); while(i!=c. end()) { Container: : iterator j= i; ++i; if(f(*j)) // f is some test { c. erase(j); . . . } �Works for set, map, list, not vector or deque

How do you know? ! �Experience �Trial and error ; ) �http: //www. cplus.

How do you know? ! �Experience �Trial and error ; ) �http: //www. cplus. com/reference/stl/ �msdn

Adaptors

Adaptors

�Container adaptors are not full container classes, but classes that provide a specific interface

�Container adaptors are not full container classes, but classes that provide a specific interface relying on an object of one of the container classes to handle the elements. �The underlying container is encapsulated in such a way that its elements are accessed by the members of the container class independently of the underlying container class used. �stack, queue and priority_queue are implemented as container adaptors. �Don’t have iterators

Stack template <class T, class Container=deque<T>> class stack; �T – stored type �Container -

Stack template <class T, class Container=deque<T>> class stack; �T – stored type �Container - the only requirement is that it supports the following operations �back() �push_back() �pop_back()

stack<T, Seq> � provides push, pop, top, size and empty � Notice that unlike

stack<T, Seq> � provides push, pop, top, size and empty � Notice that unlike java, pop is not returning a value, it's a void function. �If pop() returned the top element, it would have to return by value rather than by reference (return by reference would create a dangling pointer). �Return by value, however, is inefficient: it involves at least one redundant copy constructor call. �Since it is impossible for pop() to return a value in such a way as to be both efficient and correct, it is more sensible for it to return no value at all and to require clients to use top() to inspect the value at the top of the stack.

stack<T, Seq> int main() { stack<int> S; S. push(8); S. push(7); S. push(4); assert(S.

stack<T, Seq> int main() { stack<int> S; S. push(8); S. push(7); S. push(4); assert(S. size() == 3); assert(S. top() == 4); S. pop(); assert(S. top() == 7); S. pop(); assert(S. top() == 8); S. pop(); assert(S. empty()); }