The Standard Template Library

# The Standard Template Library

## The Standard Template Library

- - - - - - - - - - - - - - - - - - - - - - - - - - - E N D - - - - - - - - - - - - - - - - - - - - - - - - - - -
##### Presentation Transcript

1. The Standard Template Library

2. Some History The Standard Template Library was developed by Alexander Stepanov and Meng Lee at Hewlett Packard, and is based on their research on Generic Programming. Significant contributions to these ideas came from David Musser.

3. Some History Recognizing the need for a set of re-usable components that implement commonly used data structures and algorithms, the C++ standards committee added the Standard Template Library to the standard C++ library.

4. Almost all parts of the library are written as templates. Key components of the library are: Containers Iterators Algorithms

5. Remember using vectors? A vector is actually part of the Standard Template Library. It is one of the container classes in the STL. Before we dive into the STL in detail, let’s review what we know about Vectors.

6. Vectors A vector has many of the attributes of an array. In particular, elements in a vector appear as if they are stored sequentially, and can be accessed by an index into the vector. However, vectors are different from arrays because a vector will grow as required. Arrays are fixed in size.

7. Declaring a Vector vector<int> scores; The type of data to be stored in the vector. The name of the vector object. The vector is initially empty.

8. Declaring a Vector with an initial size. The size vector<int> scores(5); The type of data to be stored in the vector. The name of the vector object.

9. Storing Data in a Vector vector<int> scores(5); 0 1 2 3 4

10. Storing Data in a Vector vector<int> scores(5); 0 1 2 3 4 scores[3] = 127; 127

11. Getting Data From a Vector vector<int> scores(5); 0 1 2 3 127 4 cout << scores[3] << endl;

12. Growing a Vector vector<int> scores(5); 0 1 2 3 127 4 5 scores.push_back(119); 119

13. Vectors Vectors store their elements in an internal dynamic array. You can access any element of a vector in constant time provided you know where the element is. Vectors provide good performance when adding or deleting elements at the end, but inserting or deleting in the middle is very expensive. This is because every element behind has to be moved to a new position. Insertion time is not constant! Vectors grow as required, but “growing” a vector is expensive, and invalidates all references, pointers and iterators for elements of the vector

14. Inserting into a vector… 9 5 7 15 12 21 24

15. Growing invalidates references Vector<int>::Iterator p ??? 5 7

16. Vector Size Vectors never shrink. You can manage the size of a vector by calling c.reserve( size);

17. vector<Elem> c; vector<Elem> c1(c2); vector<Elem> c(n); creates an empty vector. creates a copy of vector c2. creates a vector of n elements created by their default constructor. This also initializes base data types to 0 Vector Constructors

18. Given a vector as our starting point, We will now discuss * Iterators * Generic Algorithms

19. Iterators An iterator is an object that can be used to navigate over the elements stored in a container. An iterator represents a certain position in a container. An iterator can be thought of as a pointer, but it removes the programmer from worrying about the details typically required when dealing with pointers.

20. ++ and -- moves the iterator to the next, or previous element both prefix and postfix operations are valid == and != used to see if two iterators point to the same location * used to dereference an iterator Operators on Iterators The following operators have been overloaded to manipulate iterators. They work on most container classes:

21. Iterator Functions All container classes provide the same basic member functions that enable them to use iterators to navigate over their elements. The most important of these are: begin( ) Returns an iterator that represents the beginning element in the container end( ) Returns a sentinel that represents the end of the elements in the container. By convention, the end is the position behind the last element.

22. Kinds of Iterators Input Output Forward Bidirectional Random

23. Kinds of Iterators Input iterators are used to read an element from a container. An input iterator only moves in the forward direction. Input Output Forward Bidirectional Random

24. Kinds of Iterators Input Output iterators are used to write an element into a container. An output iterator only moves in the forward direction. Output Forward Bidirectional Random

25. Kinds of Iterators Input Output Forward iterators combines the capabilities of input and output iterators. Forward Bidirectional Random

26. Kinds of Iterators Input Output Forward Bidirectional iterators combine the capability of a forward iterator with the ability to move backwards through the container. Bidirectional Random

27. Kinds of Iterators Input Output Forward Bidirectional Bi-directional iterators combine the capabilities of a bidirectional iterator with the ability to directly access any element in a container. Random

28. Different container classes support different kinds of iterators. Vector iterators are the most general, because all of the iterator operations work with a vector.

29. Forward the ++ operator works on the iterator Bidirectional the ++ and –- operators work on the iterator Random ++, --, and [ ] operator work on the iterator

30. Iterator Example

31. Iterator Example // some #includes … int main( ) { const int SIZE = 4; vector<int> inums; 1st – create a vector

32. Iterator Example // some #includes … int main( ) { const int SIZE = 4; vector<int> inums; for (int i = 0; i < SIZE; i++) inums.push_back(i); 1st – create a vector 2nd – fill it with values

33. Iterator Example // some #includes … int main( ) { const int SIZE = 4; vector<int> inums; for (int i = 0; i < SIZE; i++) inums.push_back(i); vector<int>::iterator p; 1st – create a vector 2nd – fill it with values 3rd – create an iterator

34. Iterator Example // some #includes … int main( ) { const int SIZE = 4; vector<int> inums; for (int i = 0; i < SIZE; i++) inums.push_back(i); vector<int>::iterator p; p = inums.begin( ); 1st – create a vector 2nd – fill it with values 3rd – create an iterator 4th – set the iterator to the beginning of the vector

35. Iterator Example // some #includes … int main( ) { const int SIZE = 4; vector<int> inums; for (int i = 0; i < SIZE; i++) inums.push_back(i); vector<int>::iterator p; p = inums.begin( ); cout << p[ 1 ] << endl; 1st – create a vector 2nd – fill it with values 3rd – create an iterator 4th – set the iterator to the beginning of the vector 5th – use the iterator to access element 1

36. Iterator Example // some #includes … int main( ) { const int SIZE = 4; vector<int> inums; for (int i = 0; i < SIZE; i++) inums.push_back(i); vector<int>::iterator p; p = inums.begin( ); cout << p[ 1 ] << endl; cout << *(p + 1) << endl; 1st – create a vector 2nd – fill it with values 3rd – create an iterator 4th – set the iterator to the beginning of the vector 5th – use the iterator to access element 1 alternate syntax

37. Using an Iterator to Move Through a Container for (p = inums.begin( ); p != inums.end( ); p++) cout << *p;

38. Constant and Mutable Iterators A constant iterator allows you to dereference the iterator to read the value pointed to. You cannot change the value. A mutable iterator allows you to dereference the iterator to read the value pointed to, or store a new value at that element.

39. Some container classes only support constant iterators. If a container supports both constant and mutable iterators, and you want a constant iterator, you must declare it as using std::vector<int>::const_iterator; . . . const_iterator p = container.begin( );

40. Iterator Adapters The Standard Template Library provides three variations on the normal iterator. These are Reverse Iterators Insert Iterators Stream Iterators

41. Reverse Iterators Given an iterator, p, you might be tempted to try for (p = container.end( ); p != container.begin( ); p--) . . . to iterate backwards through a container. However, in general this will not work, because the begin( ) function returns a real iterator while the end( ) function returns a sentinel. The specific use of the sentinel is to test whether or not you have reached the last element. It does not work like a real iterator.

42. To navigate backwards through a container, use a reverse iterator, as in the following example. reverse_iterator rp; for (rp = c.rbegin( ); rp != c.rend( ); rp++) { . . . ++ moves to the previous element! this function returns a sentinel to use when testing for the start of the container this function returns an iterator pointing to the last element in the container c

43. Insert Iterator The insert iterator adapter turns a normal assignment operation into an insert operation.

44. Back Inserter Front Inserter General Inserter These make an assignment operation work as an insertion. Inserters must be initialized with their containers when they are created. Back_insert_iterator<vector<int> > iter(collection);

45. Or you can use the function back_inserter( ) which creates the back_inserter and inserts an element at the same time. back_inserter(collection) = 45;

46. int main( ) { list<int> collection; collection.push_front(5); collection.push_front(7); front_inserter(collection) = 44; front_inserter(collection) = 60; list<int>::iterator p; for (p = collection.begin( ); p != collection.end( ); p++) { cout << *p << endl; } cin.get(); return 0; } Inserts the value at the front of the container, using the push_front function…

47. So … what’s the big deal? Consider the following code that copies one vector to another:

48. #include <vector> using std::vector; #include <algorithm> using std::copy; const int SIZE = 5;

49. int main( ) { // declare two arrays to load the vectors // arr1 contains odd digits // arr2 contains even digits int arr1[] = {1, 3, 5, 7, 9}; int arr2[] = {0, 2, 4, 6, 8}; // Now declare the vectors vector<int> odds; vector<int> evens; // The loop loads the vectors from the arrays for (int i = 0; i < SIZE; i++) { odds.push_back (arr1[i]); evens.push_back (arr2[i]); }

50. 1 3 5 7 9 odds 0 2 4 6 8 evens