home *** CD-ROM | disk | FTP | other *** search
/ More Insanity: Totally Insane 2 / totally_insane_ii.iso / src / STL / stl_introduction.txt < prev    next >
Encoding:
INI File  |  1997-05-29  |  11.5 KB  |  221 lines

  1. [Silicon Graphics, Inc.]
  2.  
  3.                 Introduction to the Standard Template Library
  4.  
  5. The Standard Template Library, or STL, is a C++ library of container
  6. classes, algorithms, and iterators; it provides many of the basic algorithms
  7. and data structures of computer science. The STL is a generic library,
  8. meaning that its components are heavily parameterized: almost every
  9. component in the STL is a template. You should make sure that you understand
  10. how templates work in C++ before you use the STL.
  11.  
  12. Containers and algorithms
  13.  
  14. Like many class libraries, the STL includes container classes: classes whose
  15. purpose is to contain other objects. The STL includes the classes vector,
  16. list, deque, set, multiset, map, multimap, hash_set, hash_multiset,
  17. hash_map, and hash_multimap. Each of these classes is a template, and can be
  18. instantiated to contain any type of object. You can, for example, use a
  19. vector<int> in much the same way as you would use an ordinary C array,
  20. except that vector eliminates the chore of managing dynamic memory
  21. allocation by hand.
  22.  
  23.       vector<int> v(3);            // Declare a vector of 3 elements.
  24.       v[0] = 7;
  25.       v[1] = v[0] + 3;
  26.       v[2] = v[0] + v[1];          // v[0] == 7, v[1] == 10, v[2] == 17
  27.  
  28. The STL also includes a large collection of algorithms that manipulate the
  29. data stored in containers. You can reverse the order of elements in a
  30. vector, for example, by using the reverse algorithm.
  31.  
  32.       reverse(v.begin(), v.end()); // v[0] == 17, v[1] == 10, v[2] == 7
  33.  
  34. There are two important points to notice about this call to reverse. First,
  35. it is a global function, not a member function. Second, it takes two
  36. arguments rather than one: it operates on a range of elements, rather than
  37. on a container. In this particular case the range happens to be the entire
  38. container v.
  39.  
  40. The reason for both of these facts is the same: reverse, like other STL
  41. algorithms, is decoupled from the STL container classes. This means that
  42. reverse can be used not only to reverse elements in vectors, but also to
  43. reverse elements in lists, and even elements in C arrays. The following
  44. program is also valid.
  45.  
  46.       double A[6] = { 1.2, 1.3, 1.4, 1.5, 1.6, 1.7 };
  47.       reverse(A, A + 6);
  48.       for (int i = 0; i < 6; ++i)
  49.         cout << "A[" << i << "] = " << A[i];
  50.  
  51. This example uses a range, just like the example of reversing a vector: the
  52. first argument to reverse is a pointer to the beginning of the range, and
  53. the second argument points one element past the end of the range. This range
  54. is denoted [A, A + 6); the asymmetrical notation is a reminder that the two
  55. endpoints are different, that the first is the beginning of the range and
  56. the second is one past the end of the range.
  57.  
  58. Iterators
  59.  
  60. In the example of reversing a C array, the arguments to reverse are clearly
  61. of type double*. What are the arguments to reverse if you are reversing a
  62. vector, though, or a list? That is, what exactly does reverse declare its
  63. arguments to be, and what exactly do v.begin() and v.end() return?
  64.  
  65. The answer is that the arguments to reverse are iterators, which are a
  66. generalization of pointers. Pointers themselves are iterators, which is why
  67. it is possible to reverse the elements of a C array. Similarly, vector
  68. declares the nested types iterator and const_iterator. In the example above,
  69. the type returned by v.begin() and v.end() is vector<int>::iterator. There
  70. are also some iterators, such as istream_iterator and ostream_iterator, that
  71. aren't associated with containers at all.
  72.  
  73. Iterators are the mechanism that makes it possible to decouple algorithms
  74. from containers: algorithms are templates, and are parameterized by the type
  75. of iterator, so they are not restricted to a single type of container.
  76. Consider, for example, how to write an algorithm that performs linear search
  77. through a range. This is the STL's find algorithm.
  78.  
  79.       template <class InputIterator, class T>
  80.       InputIterator find(InputIterator first, InputIterator last, const T& value) {
  81.           while (first != last && *first != value) ++first;
  82.           return first;
  83.       }
  84.  
  85. Find takes three arguments: two iterators that define a range, and a value
  86. to search for in that range. It examines each iterator in the range [first,
  87. last), proceeding from the beginning to the end, and stops either when it
  88. finds an iterator that points to value or when it reaches the end of the
  89. range.
  90.  
  91. First and last are declared to be of type InputIterator, and InputIterator
  92. is a template parameter. That is, there isn't actually any type called
  93. InputIterator: when you call find, the compiler substitutes the actual type
  94. of the arguments for the formal type parameters InputIterator and T. If the
  95. first two arguments to find are of type int* and the third is of type int,
  96. then it is as if you had called the following function.
  97.  
  98.       int* find(int* first, int* last, int value) {
  99.           while (first != last && *first != value) ++first;
  100.           return first;
  101.       }
  102.  
  103. Concepts and Modelling
  104.  
  105. One very important question to ask about any template function, not just
  106. about STL algorithms, is what the set of types is that may correctly be
  107. substituted for the formal template parameters. Clearly, for example, int*
  108. or double* may be substituted for find's formal template parameter
  109. InputIterator. Equally clearly, int or double may not: find uses the
  110. expression *first, and the dereference operator makes no sense for an object
  111. of type int or of type double. The basic answer, then, is that find
  112. implicitly defines a set of requirements on types, and that it may be
  113. instantiated with any type that satisfies those requirements. Whatever type
  114. is substituted for InputIterator must provide certain operations: it must be
  115. possible to compare two objects of that type for equality, it must be
  116. possible to increment an object of that type, it must be possible to
  117. dereference an object of that type to obtain the object that it points to,
  118. and so on.
  119.  
  120. Find isn't the only STL algorithm that has such a set of requirements; the
  121. arguments to for_each and count, and other algorithms, must satisfy the same
  122. requirements. These requirements are sufficiently important that we give
  123. them a name: we call such a set of type requirements a concept, and we call
  124. this particular concept Input Iterator. We say that a type conforms to a
  125. concept, or that it is a model of a concept, if it satisfies all of those
  126. requirements. We say that int* is a model of Input Iterator because int*
  127. provides all of the operations that are specified by the Input Iterator
  128. requirements.
  129.  
  130. Concepts are not a part of the C++ language; there is no way to declare a
  131. concept in a program, or to declare that a particular type is a model of a
  132. concept. Nevertheless, concepts are an extermely important part of the STL.
  133. Using concepts makes it possible to write programs that cleanly separate
  134. interface from implementation: the author of find only has to consider the
  135. interface specified by the concept Input Iterator, rather than the
  136. implementation of every possible type that conforms to that concept.
  137. Similarly, if you want to use find, you need only to ensure that the
  138. arguments you pass to it are models of Input Iterator. This is the reason
  139. why find and reverse can be used with lists, vectors, C arrays, and many
  140. other types: programming in terms of concepts, rather than in terms of
  141. specific types, makes it possible to reuse software components and to
  142. combine components together.
  143.  
  144. Refinement
  145.  
  146. Input Iterator is, in fact, a rather weak concept: that is, it imposes very
  147. few requirements. An Input Iterator must support a subset of pointer
  148. arithmetic (it must be possible to increment an Input Iterator using prefix
  149. and postfix operator++), but need not support all operations of pointer
  150. arithmetic. This is sufficient for find, but some other algorithms require
  151. that their arguments satisfy additional requirements. Reverse, for example,
  152. must be able to decrement its arguments as well as increment them; it uses
  153. the expression --last. In terms of concepts, we say that reverse's arguments
  154. must be models of Bidirectional Iterator rather than Input Iterator.
  155.  
  156. The Bidirectional Iterator concept is very similar to the Input Iterator
  157. concept: it simply imposes some additional requirements. The types that are
  158. models of Bidirectional Iterator are a subset of the types that are models
  159. of Input Iterator: every type that is a model of Bidirectional Iterator is
  160. also a model of Input Iterator. Int*, for example, is both a model of
  161. Bidirectional Iterator and a model of Input Iterator, but istream_iterator,
  162. is only a model of Input Iterator: it does not conform to the more stringent
  163. Bidirectional Iterator requirements.
  164.  
  165. We describe the relationship between Input Iterator and Bidirectional
  166. Iterator by saying that Bidirectional Iterator is a refinement of Input
  167. Iterator. Refinement of concepts is very much like inheritance of C++
  168. classes; the main reason we use a different word, instead of just calling it
  169. "inheritance", is to emphasize that refinement applies to concepts rather
  170. than to actual types.
  171.  
  172. There are actually three more iterator concepts in addition to the two that
  173. we have already discussed: the five iterator concepts are Output Iterator,
  174. Input Iterator, Forward Iterator, Bidirectional Iterator, and Random Access
  175. Iterator; Forward Iterator is a refinement of Input Iterator, Bidirectional
  176. Iterator is a refinement of Forward Iterator, and Random Access Iterator is
  177. a refinement of Bidirectional Iterator. (Output Iterator is related to the
  178. other four concepts, but it is not part of the hierarchy of refinement: it
  179. is not a refinement of any of the other iterator concepts, and none of the
  180. other iterator concepts are refinements of it.) The Iterator Overview has
  181. more information about iterators in general.
  182.  
  183. Container classes, like iterators, are organized into a hierarchy of
  184. concepts. All containers are models of the concept Container; more refined
  185. concepts, such as Sequence and Associative Container, describe specific
  186. types of containers.
  187.  
  188. Other parts of the STL
  189.  
  190. If you understand algorithms, iterators, and containers, then you understand
  191. almost everything there is to know about the STL. The STL does, however,
  192. include several other types of components.
  193.  
  194. First, the STL includes several utilities: very basic concepts and functions
  195. that are used in many different parts of the library. The concept
  196. Assignable, for example, describes types that have assignment operators and
  197. copy constructors; almost all STL classes are models of Assignable, and
  198. almost all STL algorithms require their arguments to be models of
  199. Assignable.
  200.  
  201. Second, the STL includes some low-level mechanisms for allocating and
  202. deallocating memory. Allocators are very specialized, and you can safely
  203. ignore them for almost all purposes.
  204.  
  205. Finally, the STL includes a large collection of function objects, also known
  206. as functors. Just as iterators are a generalization of pointers, function
  207. objects are a generalization of functions: a function object is anything
  208. that you can call using the ordinary function call syntax. There are several
  209. different concepts relating to function objects, including Unary Function (a
  210. function object that takes a single argument, i.e. one that is called as
  211. f(x)) and Binary Function (a function object that takes two arguments, i.e.
  212. one that is called as f(x, y)). Function objects are an important part of
  213. generic programming because they allow abstraction not only over the types
  214. of objects, but also over the operations that are being performed.
  215.  
  216. ----------------------------------------------------------------------------
  217.  [Silicon Surf]    [STL Home]
  218.  
  219. Copyright ⌐ 1996 Silicon Graphics, Inc. All Rights Reserved.
  220. TrademarkInformation webmaster@www.sgi.com
  221.