0 оценок0% нашли этот документ полезным (0 голосов)
22 просмотров55 страниц
"The Standard Template Library" is a C++ programming library that has been developed by Alexander Stepanov and Meng Lee at the Hewlett a!"ard laboratories in alo alto# california%. The library is based on the extensive'se o$ templates (also!alled parametri)ed types%. This paper tries to give a!omprehensive and complete s'rvey on the STL programming paradigm and shall
"The Standard Template Library" is a C++ programming library that has been developed by Alexander Stepanov and Meng Lee at the Hewlett a!"ard laboratories in alo alto# california%. The library is based on the extensive'se o$ templates (also!alled parametri)ed types%. This paper tries to give a!omprehensive and complete s'rvey on the STL programming paradigm and shall
"The Standard Template Library" is a C++ programming library that has been developed by Alexander Stepanov and Meng Lee at the Hewlett a!"ard laboratories in alo alto# california%. The library is based on the extensive'se o$ templates (also!alled parametri)ed types%. This paper tries to give a!omprehensive and complete s'rvey on the STL programming paradigm and shall
!ohanne" Weidl Information Systems Institute Distributed Systems Department Technical University Vienna Friday, 26. April 1996 Advisor Dipl. Ing. Georg Trausmuth Professor DI Dr. ehdi !a"ayeri "The Standard Template Library (STL) is a C++ programming library that has been developed by Alexander Stepanov and Meng Lee at the Hewlett a!"ard laboratories in alo Alto# Cali$ornia% &t was designed to enable a C+ + programmer to do generi! programming and is based on the extensive 'se o$ templates ( also !alled parametri)ed types% This paper tries to give a !omprehensive and !omplete s'rvey on the STL programming paradigm and shall serve as step(by(step t'torial $or the STL new!omer# who has $'ndamental "nowledge in C++ and the ob*e!t(oriented paradigm%" Table of contents 1 Introduction________________________________________________________________ 2 C++ basics__________________________________________________________________ #.1 $la""e"%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% #.# &unction ob'ect"%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% #.3 Template"%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% #.$.% &unction templates''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' #.$.# (lass templates'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' #.$.$ Template member functions'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' #.$.) Template speciali"ation'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' 3 A STL overview______________________________________________________________ 3.1 STL a(ailability and information%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% $.%.% &TP*Sites''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' $.%.# U+,s'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' 3.# What doe" STL con"i"t of)%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 3.3 $ompilin* STL pro*ram"%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% $.$.% -orland (.. )./ D0S*programs'''''''''''''''''''''''''''''''''''''''''''''''''''''''''' $.$.# -orland (.. )./ 1I2D01S*programs'''''''''''''''''''''''''''''''''''''''''''''''''''' $.$.$ -orland (.. ).3 D0S* and 1I2D01S*programs'''''''''''''''''''''''''''''''''''''''''''' 4 Learning STL_______________________________________________________________ 4.1 $ontainer"%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ).%.% Vector'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' ).%.# 45ercises''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' 4.# +terator"%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ).#.% Input Iterators and 0utput Iterators'''''''''''''''''''''''''''''''''''''''''''''''''''''''' ).#.# &or6ard Iterators'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' ).#.$ -idirectional Iterators''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' ).#.) +andom Access Iterators'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' ).#.3 45ercises''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' 4.3 ,l*orithm" and &unction -b'ect"%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ).$.% 7o6 to create a generic algorithm''''''''''''''''''''''''''''''''''''''''''''''''''''''''' ).$.# The ST, algorithms'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' ).$.$ 45ercises''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' 4.4 ,daptor"%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ).).% (ontainer Adaptors''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' ).).# Iterator Adaptors''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' ).).$ &unction Adaptors'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' 4.. ,llocator" and memory handlin*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 5 The remaining STL comonents________________________________________________ 3.% 7o6 components 6or8 together'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' 3.# Vector''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' 3.$ ,ist''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' 3.) De9ue''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' 3.3 Iterator Tags'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' 3.: Associative (ontainers'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' ! Co"right__________________________________________________________________ # Literature__________________________________________________________________ STL Tutorial page 2 Johannes Weidl 1 Introduction /oti(ation. In the late ;/s Ale5ander Stepanov first observed that some algorithms do not depend on some particular implementation of a data structure but only on a fe6 fundamental semantic properties of the structure. Such properties can be * for e5ample * the ability< to get from one element of the data structure to the ne5t< and to be able to step through the elements from the beginning to the end of the structure. &or a sort algorithm it is not essential if the elements to be sorted are stored in an array< a lin8ed list< etc. Stepanov e5amined a number of algorithms and found that most of them could be abstracted a6ay from a particular implementation and that this abstraction can be done in a 6ay that efficiency is not lost. 4fficiency is an essential point that Stepanov emphasi"es on< he is convinced that no one 6ould use an algorithm that becomes inefficient by instantiating it bac8. The STL hi"tory. Stepanovs insight * 6hich hasn=t had much influence on soft6are development so far * 6ill lead to a ne6 programming paradigm in future * so the hope of its discoverer. In %>?3 Stepanov developed a generic Ada library and 6as as8ed< if he could do this in (.. as 6ell. -ut in %>?; templates @see section #.$A * an essential techni9ue for this style of programming * 6eren=t implemented in (.. and so his 6or8 6as delayed. In %>?? Stepanov moved to the 7P ,abs and %>># he 6as appointed as manager of an algorithm proBect. 1ithin this proBect< Ale5ander Stepanov and eng ,ee 6rote a huge library * the Standard Template ,ibrary @ST,A * 6ith the intention to sho6 that one can have algorithms defined as generically as possible 6ithout losing efficiency. STL and the ,0S+1+S- $22 3raft Standard. The importance of ST, is not only founded in its creation or e5istence< ST, 6as adopted into the draft standard at the !uly %)< %>>) A2SICIS0 (.. Standards (ommittee meeting. That means that if not happened till no6 any6ay< compiler vendors 6ill soon be incorporating ST, into their products. The broad availability of ST, and the generic programming idea give this ne6 programming paradigm the chance to positively influence soft6are development * thus allo6 programmers to 6rite code faster and to 6rite less lines of code 6hile focusing more on problem solution instead of 6riting lo6*level algorithms and data structures. 3ocument arran*ement. In section # ST,*re9uired (.. basics are taught< especially classes< function obBect design and templates * also called parametri"ed types. In section $ ST, is overvie6ed and the 8ey concepts are e5plained. Section ) teaches ST, step*by*step. Section 3 deals 6ith ST, components not e5plained in section ). Section : contains copyright notices and section ; sho6s the literature used. 2 C++ basics STL "pecific $22 ba"ic". This section gives a short survey on ST,*re9uired (.. basics< such as classes< function obBects and templates. It tries to point out the ST,*specific aspects. &or a fundamental and comprehensive study and understanding of these topics read D%E< F3 to F?. 2.1 Classes 4"er5defined type". 0ne reason to develop ( into (.. 6as to enable and encourage the programmer to use the obBect*oriented paradigm. GThe aim of the (.. class concept D...E is to provide the programmer 6ith a tool for creating ne6 types that can be used as conveniently as the built*in typesG< says -Barne Stroustrup< the father of (..< in D%E. It is stated that a class is a user*defined typeH STL Tutorial page 3 Johannes Weidl class shape { private: int x_pos; int y_pos; int color; public: shape () : x_pos(0), y_pos(0), color(1) {} shape (int x, int y, int c = 1) : x_pos(x), y_pos(y), color(c) {} shape (const shape& s) : x_pos(s.x_pos), y_pos(s.y_pos), color(s.color) {} shape () {} shape& operator= (const shape& s) { x_pos = s.x_pos, y_pos = s.y_pos, color = s.color; return this; } int !et_x_pos () { return x_pos; } int !et_y_pos () { return y_pos; } int !et_color () { return color; }
voi" set_x_pos (int x) { x_pos = x; } voi" set_y_pos (int y) { y_pos = y; } voi" set_color (int c) { color = c; } virtual voi" #ra$%hape () {} &rien" ostrea'& operator(( (ostrea'& os, const shape& s); }; ostrea'& operator(( (ostrea'& os, const shape& s) { os (( )shape: () (( s.x_pos (( ),) (( s.y_pos (( ),) (( s.color (( ))); return os; } 67aminin* the $22 cla"" 8"hape8. The 8ey6ord class begins the definition of the user*defined type. The 8ey6ord private means that the names x_pos, y_pos and color can only be used by member functions @6hich are functions defined inside the class definitionA. The 8ey6ord public starts the public*section< 6hich constitutes the interface to obBects of the class< that means< names and member functions in this section can be accessed by the user of the obBect. -ecause of the attributes being private< the class has public member functions to get and set the appropriate values. These member functions belong to the interface. 2ote that a class is abstract< 6hereas the instantiation of a class leads to an obBect< 6hich can be used and modifiedH shape *y%hape (1+, 10, ,); int color = *y%hape.!et_color(); shape -e$%hape = *y%hape; 6here shape is the class name and *y.lass is an obBect of the class shape. shape () : x_pos(0), y_pos(0), color(1) {} is the default constructor * the constructor 6ithout arguments. A constructor builds and initiali"es an obBect< and there are more possible 8inds of constructorsH shape (int x, int y, int c = 1) : x_pos(x), y_pos(y), color(c) {} This is a constructor 6ith three arguments 6here the third one is a default argumentH shape *y%hape (10, 10); results inH x_pos == 10< y_pos == 10< color == 1. STL Tutorial page 4 Johannes Weidl shape (const shape& s) : x_pos(s.x_pos), y_pos(s.y_pos), color(s.color) {} This is an important constructor< the so*called copy*constructor. It is called 6hen you 6rite code li8e thisH shape *y%hape; shape -e$%hape (*y%hape); After that< *y%hape and -e$%hape have the same attributes< the obBect -e$%hape is copied from the obBect *y%hape using the copy constructor. 2ote the argument const shape& s. The I means Greference toG< 6hen a function call ta8es place< the shape is not copied onto the stac8< but only a reference @pointerA to it. This is important< 6hen the obBect given as argument is huge< because then copying 6ould be very inefficient. shape () {} is the destructor. It is called< 6hen an obBect is destroyed * for e5ample 6hen it goes out of scope. The shape destructor has nothing to do< because inside the shape class no dynamically allocated memory is used. shape& operator= (const shape& s) { x_pos = s.x_pos, y_pos = s.y_pos, color = s.color; return this; } -perator o(erloadin*. In (.. it is possible to overload operators * that is to give them a ne6 meaning or functionality. There is a set of operators 6hich can be defined as member functions inside a class. Among these the assignment operator can be found< 6hich is used 6hen 6riting the follo6ing codeH shape *y%hape, -e$%hape; -e$%hape = *y%hape; 2ote that the operator= is called for the left obBect< i.e. -e$%hape< so there must be only one argument in the declaration. This is true for all other (.. operators as 6ell. 1hen a member function is called< the system automatically adds the this*pointer to the argument list. The this*pointer points to the obBect< for 6hich the member function is called. -y 6riting return this< the concatenation of assignments gets possibleH shape /l"%hape, *y%hape, -e$%hape; -e$%hape = *y%hape = /l"%hape; int !et_x_pos () { return x_pos; } gives you the value of x_pos. An e5plicit interface function is necessary< because private mebers cannot be accessed from outside the obBect. virtual voi" #ra$%hape () {} declarates a function 6ith no arguments that dra6s the shape. -ecause a shape is abstract and 6e have no idea of 6hat it loo8s li8e precisely< thereJs no implementation for #ra$%hape. The 8ey6ord virtual means that this member function can be over6ritten in a derived class @see D%E< F:A. &or e5ample< a class "ot could be derived from shape. #ra$%hape then 6ould be over6ritten to dra6 the dot at the position @x_pos<y_posA and 6ith the colour color. STL Tutorial page Johannes Weidl 9ut5to operator. 2o6 consider the definition of the operator((H ostrea'& operator(( (ostrea'& os, const shape& s) { os (( )shape: () (( s.x_pos (( ),) (( s.y_pos (( ),) (( s.color (( ))); return os; } The usual 6ay in (.. to display information on the screen is to 6riteH cout (( )0ello, 1orl"2); 1ith the upper code 6e overload the p't(to(operator @operator((A to be able to send shapes directly to an output streamH shape *y%hape (3, 4); cout (( *y%hape; sho6s on the output screenH shape+ (,#-#.) &rien" ostrea'& operator(( (ostrea'& os, const shape& s); &riend and inline. The 8ey6ord &rien" in front of a function declaration means that this function has access to the private members of the class< 6here the declaration ta8es place. Kou can see that x_pos< y_pos and color are used directly by operator((. It=s also possible to define a 6hole class as $riend class. 2ote that all member functions of shape are defined inside the class declaration. If so< the member functions are all GinlineG. &nline means< that 6herever the function is called< the compiler creates no function call but inserts the code directly to decrease overhead. To inline a member function defined outside the class the 8ey6ord inline must be usedH inline int shape::!et_x_pos () { return x_pos; } 0ice $la""e". &or ST, it=s 6ise to create classes that meet the re9uirements of /i!e Classes. &or e5ample< -orland (.. e5pects an obBect to be stored in a container to have an assignment operator defined. Additionally< if a container holds its obBects in a particular order< a operator li8e the operator( must be defined @the latter to fi5 a half*orderA. A class T is called ni!e iff it supportsH 1. (opy constructor 5 (const 5&) +. Assignment operator 5& operator= (const 5&) 6. 49uality operator int operator== (const 5&, const 5&) ,. Ine9uality operator int operator2= (const 5&, const t&) such thatH 1. 5 a(b); assert (a == b); +. a = b; assert (a == b); 6. a == a; ,. a == b i&& b == a 3. (a == b) && (b == c) i'plies (a == c) 7. a 2= b i&& 2 (a == b) STL Tutorial page ! Johannes Weidl A member function 5::s(...) is called e0'ality preserving iff a == b i'plies a.s (...) == b.s (...) A class is called 45tra*2ice iff all of its member functions are e9uality preserving The theory of 2ice (lasses origins from a Boint 6or8 bet6een 7P and Andre6 Loenig from the -ell ,abs. 2.2 "unction ob#ects The function5call operator. A function obBect is an obBect that has the $'n!tion(!all operator @operator() A defined @or overloadedA. These function obBects are of crucial importance 6hen using ST,. (onsider an e5ampleH class less { public: less (int v) : val (v) {} int operator () (int v) { return v ( val; } private: int val; }; This function obBect must be created by specifying an integer valueH less less_than_&ive (3); The constructor is called and the value of the argument v is assigned to the private member val. 1hen the function obBect is applied< the return value of the overloaded function call operator tells if the argument passed to the function obBect is less than valH cout (( )+ is less than 3: ) (( (less_than_&ive (+) 8 )yes) : )no)); 0utputH 1 is less than ,+ yes Kou should get familiar 6ith this 8ind of programming< because 6hen using ST, you often have to pass such function obBects as arguments to algorithms and as template arguments 6hen instantiating containers< respectively. 2.3 Te$plates Static type checkin*. (.. is a language that supports static type chec8ing. Static type chec8ing helps to catch many errors during compilation< because the programmer has to fi5 the type of a name used. Any violation of the type model leads to an error message and cancels compilation. So< run*time errors decrease. STL Tutorial page % Johannes Weidl 2.3.1 "unction te$plates (onsider the follo6ing functionH voi" s$ap (int& a, int& b) { int t'p = a; a = b; b = t'p; } S:appin* inte*er". This function let=s you s6ap the contents of t6o integer variables. -ut 6hen programming 9uite a big application< it is probable that you have to s6ap float< long or char variables< or even shape variables * as defined in section #. So< an obvious thing to do 6ould be to copy the piece of code @cut*n*pasteMA and to replace all ints by shapes< 6ouldn=t itN A dra6bac8 of this solution is the number of similar code pieces< that have to be administered. Additionally< 6hen you need a ne6 s6ap function< you must not forget to code it< other6ise you get a compile*time error. And no6 imagine the overhead 6hen you decide to change the return type from voi" to int to get information< if the s6ap 6as successful * the memory could be too lo6 to create the local t'p variable< or the assignment operator @see shapeA could not be defined. Kou 6ould have to change all 5 versions of s$ap * and go insane... Template" or 9arametri;ed type". The solution to this dar8*dra6n scenario are templates< template functions are functions that are parametri"ed by at least one type of their argumentsH te'plate (class 59 voi" s$ap (5& a, 5& b) { 5 t'p = a; a = b; b = t'p; } 2ote that the T is an arbitrary type*name< you could use U or anyType as 6ell. The arguments are references to the obBects< so the obBects are not copied to the stac8 6hen the function is called. 1hen you 6rite code li8e int a = 6, b = 3; shape *y%hape, :our%hape; s$ap (a, b); s$ap (*y%hape, :our%hape); the compiler GinstantiatesG the needed versions of s$ap< that means< the appropriate code is generated. There are different template instantiation techni9ues< for e5ample manual instantiation< 6here the programmer himself tells the compiler< for 6ich types the template should be instantiated. &unction template e7ample". 0ther e5amples for function templates areH te'plate (class 59 5& 'in (5& a, 5&b) { return a ( b 8 a : b; } te'plate (class 59 voi" print_to_cout (char 's!, 5& ob;) { cout (( 's! (( ): ) (( ob; (( en"l; } STL Tutorial page & Johannes Weidl To use the last template function< obBects given as the second argument must have the operator(( defined< other6ise you 6ill get a compile*time error. 2.3.2 Class te$plates $la"" template" to build container". The motivation to create class templates is closely related to the use of containers. G7o6ever< container classes have the interesting property that the type of obBects they contain is of little interest to the definer of a container class< but of crucial importance to the user of the particular container. Thus 6e 6ant to have the type of the contained obBect be an argument to a container classH D...EG< D%E< F?. That means that a container * e.g. a vector * should be able to contain obBects of any type. This is achieved by class templates. The follo6ing e5ample comes from D%E< F%.).$H te'plate (class 59 class vector { 5 v; int s<; public: vector (int s) { v = ne$ 5 =s< = s>; } vector () { "elete=> v; } 5& operator=> (int i) { return v=i>; } int !et_si<e() { return s<; } }; 2ote that no error*chec8ing is done in this e5ample. Kou can instantiate different vector* containers 6hich store obBects of different typesH vector(int9 int_vector (10); vector(char9 char_vector (10); vector(shape9 shape_vector (10); Ta8e a loo8 at the notation< the type*name is ve!tor2spe!i$i!3type4% 2.3.3 Te$plate $e$ber functions -y no6 there=s no compiler I 8no6 6hich could handle template member functions. This 6ill change in the very future< because template member functions are designated in the (.. standard. 2.3.4 Te$plate speciali'ation $ope :ith "pecial type feature". If there is a good reason< 6hy a compiler*generated template for a special type does not meet your re9uirements or 6ould be more efficient or convenient to use 6hen implemented in another 6ay< you can give the compiler a special implementation for this type * this special implementation is called template spe!iali)ation. &or e5ample< 6hen you 8no6< that a shape*vector 6ill al6ays hold e5actly one obBect< you can speciali"e the vector*template as follo6sH STL Tutorial page ( Johannes Weidl class vector(shape9 { shape v; public: vector (shape& s) : v(s) { } shape& operator=> (int i) { return v; } int !et_si<e() { return 1; } }; ,et=s use itH shape *y%hape; vector(shape9 sin!le_shape_vector (*y%hape); Template speciali"ations can also be provided for template functions @D%E< Fr.%).3A and template operators. STL Tutorial page 1) Johannes Weidl 3 * STL o+er+ie, ST, is a component library. This means that it consists of components * clean and formally sound concepts. Such components are for e5ample containers * that are obBects 6hich store obBects of an arbitrary type * and algorithms. -ecause of the generic approach ST, algorithms are able to 6or8 on user*built containers and user*built algorithms can 6or8 on ST, containers * if the user ta8es some strict re9uirements for building his components into consideration. This techni9ue * to guarantee the interoperability bet6een all built*in and user*built components * is referred to as Gthe orthogonal decomposition of the component spaceG. The idea behind ST, can easily be sho6n by the follo6ing considerationH Imagine soft6are components as a three*dimensional space. 0ne dimension represents the data types @int< double< char< ...A< the second dimension represents the containers @array< lin8ed*list< ...A and the third dimension represents the algorithms @sort< merge< search< ...A. Figure 1: Component space 1ith this scenario given< iOBO8 different versions of code have to be designed * a sort algorithm for an array of int< the same sort algorithm for an array of double< a search algorithm for a lin8ed*list of double and so on. -y using template functions that are parametri"ed by a data type< the i*a5es can be dropped and only BO8 versions of code have to be designed< because there has to be only one lin8ed*list implementation 6hich then can hold obBects of any data*type. The ne5t step is to ma8e the algorithms 6or8 on different containers * that means that a search algorithm should 6or8 on arrays as 6ell as on lin8ed*lists< etc. Then< only B.8 versions of code have to be created. ST, embodies the above concept and is thus e5pected to simplify soft6are development by decreasing development times< simplifying debugging and maintenance and increasing the portability of code. ST, consists of five main components. 1hen I list them here< don=t get confused by the names and their short description< they are e5plained one by one in detail later. AlgorithmH computational procedure that is able to 6or8 on different containers (ontainerH obBect that is able to 8eep and administer obBects IteratorH abstraction of the algorithm*access to containers so that an algorithm is able to 6or8 on different containers &unction 0bBectH a class that has the function*call operator @operator() A defined AdaptorH encapsulates a component to provide another interface @e.g. ma8e a stac8 out of a listA At this point I recommend to read D#E< chapters % to ). 3.1 STL a+ailabilit- and infor$ation 3.1.1 "T./Sites STL Tutorial page 11 Johannes Weidl int< double< char< ... array< lin8ed*list< ... sort< merge< search< ... i ' k The 7e6lett Pac8ard ST, by Ale5ander Stepanov and eng ,ee can be found atH ftpHCCbutler.hpl.hp.comCpubCstlCstl."ip for -orland (.. ).5 ftpHCCbutler.hpl.hp.comCpubCstlCsharfile.P for G(( There are many other interesting things there< too. An alternative site is ftpHCCftp.cs.rpi.eduCstl This document deals 6ith the 7P implementation of ST,< but there are others toH 0bBectSpace ST,QToolLitR &S&CG2U libg.. #.:.#H ftpHCCprep.ai.mit.eduCpubCgnuClibg..*#.:.#.tar.g" -oth 6or8 6ith the G2U (.. compiler G(( #.:.$ that can be found atH ftpHCCprep.ai.mit.eduCpubCgnuCgcc*#.:.$.tar.g" 4specially for the 6or8 6ith 0bBectSpace ST,QToolLitR you should patch your G(( #.:.$ 6ith the template fi5 that can be found at ftpHCCftp.cygnus.comCpubCg..Cgcc*#.:.$*template*fi5 any e5amples for the 0bBectSpace ST,QToolLitR can be found at ftpHCCbutler.hpl.hp.comCpubCstlCe5amples.g" @also ."ipA 3.1.2 01Ls David ussers ST,*pageH httpHCC666.cs.rpi.eduCmusserCstl.html umit=s ST, 2e6bie guideH httpHCC666.5raylith.6isc.eduC8hanCsoft6areCstlCST,.ne6bie.html !oseph K. ,aurino=s ST, pageH httpHCC6eber.u.6ashington.eduCbyte6aveCbyte6ave'stl.html STL Tutorial page 12 Johannes Weidl 3.2 What does STL consist of2 7ere comes a list of the files included in the 7P*ST, .PIP pac8age 6ith the 7AS7 e5tensionH D0(.PS ST, Document D#E D0(-A+.PS ST, Document D#E 6ith changebars from the previous version IP.PS &I,4S.DI& Differences to the files of the previous version +4AD.4 Information file +4AD4.0,D Information file of the previous version A,G0.7 algorithm implementations A,G0-AS4.7 au5iliary algorithms for A,G0.7 IT4+AT0+.7 iterator implementations and iterator adaptors &U2(TI02.7 operators< functions obBects and function adaptors T+44.7 implementation of a red*blac8 tree for associative containers -00,.7 defines bool type PAI+.7 defines pair type to hold t6o obBects T+IP,4.7 defines triple type to hold three obBects 74AP.7 heap algorithms STA(L.7 includes all container adaptors 7AS7.7 hash implementation 7AS7-AS4.7 hashbase implementation needed by hash T4P-U&.(PP au5iliary buffer for get'temporary'bufferH should be complied and lin8ed if get'temporary'buffer< stable'partition< inplace'merge or stable'sort are used T4P-U&.7 get'temporary'buffer implementation P+0!4(T2.7 select%st and ident implementation +A2D0.(PP random number generator< should be compiled and lin8ed if random'shuffle is used D4&A,,0(.7 default allocator to encapsulate memory model -V4(T0+.7 bit vector @vector template speciali"ationA< se9uence container D4SU4.7 double ended 9ueue< seu9ence container ,IST.7 list< se9uence container AP.7 map< associative container U,TIAP.7 multimap< associative container S4T.7 set< associative container U,TIS4T.7 multiset< associative container V4(T0+.7 vector< se9uence container 3o"1Windo:" specific include filesH <u*e memory modelH 7UGA,,0(.7< 7D4SU4.7< 7,IST.7< 7AP.7< 7U,TAP.7< 7U,TS4T.7< 7S4T.7< 7V4(T0+.7 &ar memory modelH &A+A,,0(.7< &D4SU4.7< &,IST.7< &AP.7< &U,TAP.7< &U,TS4T.7< &S4T.7 Lar*e memory modelH ,2GA,,0(.7< ,-V4(T0+.7< ,D4SU4.7< ,,IST.7< ,AP.7< ,U,TAP.7< ,U,TS4T.7< ,S4T.7 0ear memory modelH 24+A,,0(.7< 2AP.7< 2U,TAP.7< 2U,TS4T.7< 2S4T.7 Table 1: STL include and documentation files 3.3 Co$piling STL progra$s 3.3.1 3orland C++ 4.) 45S/progra$s STL Tutorial page 13 Johannes Weidl $ommand Line. Assume a (.. program named vector.cppH ?"e&ine __*@-*AB_#CD@-C# EE use %5FGs !eneric 'in an" 'ax te'plates ?"e&ine __H%C_%5F EE exclu"e I.JJGs re"un"ant operator "e&initions EE %5F inclu"e &iles K inclu"e %5F &iles &irst2 ?inclu"e )vector.h) EE .JJ stan"ar" inclu"e &iles ?inclu"e (st"lib.h9 EE st"lib 'in an" 'ax &unctions are sLippe" ?inclu"e (cstrin!.h9 EE only co'pilable $ith __H%C_%5F "irective ?inclu"e (classlibMalloctr.h9 EE only co'pilable $ith __H%C_%5F "irective ?inclu"e (iostrea'.h9 voi" 'ain (voi") { vector(int9 v(3); v=0> = ,; cout (( )Dirst vector ele'ent: ) (( v=0>; } The compiler directive ?"e&ine __*@-*AB_#CD@-C# prevents the compilation of the 'in and 'ax functions in the -orland (.. include file (st"lib.h9< because ST, provides its o6n template 'in and 'ax functions. I recommend to include all ST, include files before the -orland (.. standard include files< although this causes some 6or8 to be done. There are some changes to be made in the include files (bc,Minclu"eMcstrin!.h9 and (bc,Minclu"eMclasslibMalloctr.h9< if you plan to use them. Some operator definitions have to be ta8en out of compilation< for e5ample by adding ?i& 2"e&ine" (__H%C_%5F) =...> ?en"i&, because ST, generates these operators automatically using template operator definitions. The code after adding the necessary ?i& directives @italic lettersA is sho6n in the follo6ing bo5. The line numbers indicate the operator*definition*positions in the original include filesH <bc4\include\cstring.h>: line 724: #if !defined(__USE_STL) inline int _N5FC-5N: operator 2= ( const strin! _DAN &s1, const strin! _DAN &s+ ) 50N/1_-/-C { =...> } #endif line 850: #if !defined(__USE_STL) inline int _N5FC-5N: operator (= ( const strin! _DAN &s1, const strin! _DAN &s+ ) 50N/1_-/-C { =...> } #endif line 866: #if !defined(__USE_STL) inline int _N5FC-5N: operator 9 ( const strin! _DAN &s1, const strin! _DAN &s+ ) 50N/1_-/-C { =...> } #endif STL Tutorial page 14 Johannes Weidl line 882: #if !defined(__USE_STL) inline _N5FC-5N: operator 9= ( const strin! _DAN &s1, const strin! _DAN &s+ )50N/1_-/-C { =...> } #endif <bc4\include\classlib\alloctr.h>, line 44: #if !defined(__USE_STL) &rien" voi" operator ne$( unsi!ne", voi" ptr ) { return ptr; } #endif (ompile and lin8 .cpp files using ST, 6ith the follo6ing commandH bcc K@(pathKtoKstlK"irectory9 (&ile9.cpp 45ampleH bcc K@c:Mbc,Mstl vector.cpp It is also possible to include the ST, include files after the -orland (.. standard include files< then programs 6ould even compile 6ithout having changes in (bc,Minclu"eMcstrin!.h9. -ut ST, provides a number of template functions that increase genericity and template operator definitions that generate operator2= out of operator== and operators 9< 9=< (= out of operator(< so it seems advisable to choose the practice sho6n above. +36 (+nte*rated 3e(elopment 6n(ironment. (reate a proBect specifying GD0S*StandardG as target*platform. Specify the ST,*directory under GoptionsCproBectCdirectoriesG @germanH G0ptionenCProBe8tCVer"eichnisseGA as include* directory. Use the ?"e&ine __*@-*AB_#CD@-C# statement 6hen (st"lib.h9 is included< use ?"e&ine __H%C_%5F 6hen (cstrin!.h9 and (classlibMalloctr.h9 are included. 3.3.2 3orland C++ 4.) WI645WS/progra$s As under D0S< the ?"e&ine __*@-*AB_#CD@-C# statement is needed 6hen (st"lib.hR is included. Use ?"e&ine __H%C_%5F to compile your programs< 6hen using (cstrin!.h9 and (classlibMalloctr.h9. Don=t forget to specify the ST,*directory as include*directory under GoptionsCproBectCdirectoriesG @germanH G0ptionenCProBe8tCVer"eichnisseGA. 45ample programH ?"e&ine __*@-*AB_#CD@-C# EE use %5FGs !eneric 'in an" 'ax te'plates ?"e&ine __H%C_%5F EE exclu"e I.JJGs re"un"ant operator "e&initions EE %5F inclu"e &iles ?inclu"e )vector.h) ?inclu"e )al!o.h) EE .JJ stan"ar" inclu"e &iles ?inclu"e (st"lib.h9 EE st"lib 'in an" 'ax &unctions are sLippe" ?inclu"e (cstrin!.h9 EE only co'pilable $ith __H%C_%5F "irective ?inclu"e (classlibMalloctr.h9 EE only co'pilable $ith __H%C_%5F "irective EE /1F+ inclu"e &iles ?inclu"e (o$lMo$lpch.h9 ?inclu"e (o$lMapplicat.h9 STL Tutorial page 1 Johannes Weidl int /$l*ain(int Ear!cE, char Ear!vE =>) { return 5Application().o'pile" $ith %5F inclu"e &iles)).Nun(); } I encountered some problems 6hen compiling 6indo6s programs that ma8e e5tensive use of ST, containers. The compiler comes up 6ith the error messages )co"e se!'ent excee"s 7,L) and )text se!'ent excee"s 7,L). The problem can be fi5ed by using the statements ?pra!'a co"ese! (co"ese!_na'e9 co"e and ?pra!'a co"ese! (textse!_na'e9 text< respectively. 3.3.3 3orland C++ 4. 45S/ and WI645WS/progra$s &or programs 6ritten in -orland (.. ).3 all information given in sections $.$.% and $.$.# can be applied but there are some further pointsH The first include file has to be (classlibM"e&s.h9< because there -orland (.. defines its bool type. Then< all ST, include files have to be included @before any -orland (.. include filesA. 2ote< that the line numbers of operators that have to be commented out by a ?"e&ine __H%C_%5F directive in the include files (cstrin!.h9 and (classlibMalloctr.h9 are not the same as given in section $.$.% for the appropriate -orland (.. )./ include files. A further operator has to be e5cluded by a ?"e&ine __H%C_%5F directive in the include file (o$lMbitset.h9 @found at the end of the include fileA< if it is used. D0S*e5ample @analogous for 1indo6sAH ?"e&ine __*@-*AB_#CD@-C# EE use %5FGs !eneric 'in an" 'ax te'plates ?"e&ine __H%C_%5F EE exclu"e I.JJGs re"un"ant operator "e&initions ?inclu"e (classlibM"e&s.h9 EE use I.JJ,.3 bool "e&inition EE %5F inclu"e &iles ?inclu"e )vector.h) EE .JJ stan"ar" inclu"e &iles ?inclu"e (st"lib.h9 ?inclu"e (cstrin!.h9 ?inclu"e (classlibMalloctr.h9 ?inclu"e (o$lMbitset.h9 ?inclu"e (iostrea'.h9 voi" 'ain (voi") { vector(int9 v(1, ,); cout (( v=0>; } STL Tutorial page 1! Johannes Weidl 4 Learning STL 4.1 Containers As -Barne Stroustrup says< G0ne of the most useful 8inds of classes is the container class< that is< a class that holds obBects of some @otherA typeG< D%E< F?.%. (ontainers form one crucial component of ST,. To sum up elements of a special type in a data structure< e.g. temperature values of an engine over a definite distance of time< is a crucial tas8 6hen 6riting any 8ind of soft6are. (ontainers differ in the 6ay ho6 the elements are arranged and if they are sorted using some 8ind of 8ey. In ST, you find Se0'en!e Containers and Asso!iative Containers. As described in D#E< GA se9uence is a 8ind of container that organi"es a finite set of obBects< all of the same type< into a strictly linear arrangementG. ST, provides three basic 8inds of Se9uence (ontainersH 5e!tors< Lists and 6e0'es< 6here De9ue is an abbreviation for 6o'ble 7nded 8'e'e. Figure 2: Sequence Container As Stepanov states< GAssociative containers provide an ability for fast retrieval of data based on 8eysG. The elements are sorted and so fast binary search is possible for data retrieval. ST, provides four basic 8inds of Associative (ontainers. If the 8ey value must be uni9ue in the container< this means< if for each 8ey value only one element can be stored< Set and Map can be used. If more than one element are to be stored using the same 8ey< M'ltiset and M'ltimap are provided. Figure 3: Associative Container 7ere is a summary including all containers provided by ST,H Se=uence $ontainer" >ector 3e=ue Li"t ,""ociati(e $ontainer" Set /ulti"et /ap /ultimap Table 2: STL Containers 4.1.1 7ector Assume 6e 6ant to develop a Graphical User Interface for a control station in an electric po6er station. The single elements< li8e turbines< pipes and electrical installations are sho6n STL Tutorial page 1% Johannes Weidl Andy ary Peter Tom !ohn !ohn Peter ary Andy Tom on a screen. &or each po6er station element 6e derive a special class from the shape class in section # to represent its loo8 on the screen. The class hierarchy could loo8 li8e thisH Figure 4: !ample s"ape class "ierarc"# 1e store all shapes that are sho6n on a certain screen in the appropriate shape*container< e.g. all turbine obBects that are sho6n on the main screen in a turbine*container. 1hen the screen is called< the containers are used to dra6 a representation of the appropriate part of the po6er station. In (.. one could use an arrayH turbine 'ain_screen_turbines ='ax_si<e>; 6here 'ax_si<e is the ma5imum number of turbine obBects that can be stored in the 'ain_screen_turbines array. 1hen you use ST,< you 6ould choose thisH ?inclu"e (vector.h9 typ"e& int turbine; EE so $e "onOt have to "e&ine the turbine class int 'ain() { vector(turbine9 'ain_screen_turbines; return 0; } 0ote? To ma8e this little e5ample run you have to read section $.$ on ho6 to compile ST, programs. To use a vector in your program< include vector.h. In the follo6ing e5amples only the essential code lines are presented and most of the include stuff and the main function are omitted. As you can see< you don=t have to specify a ma5imum si"e for the vector< because the vector itself is able to dynamically e5pand its si"e. The ma5imum si"e the vector can reach * i.e. the ma5imum number of elements it is able to store * is returned by the member function 'ax_si<e() of the vector classH vector(turbine9::si<e_type 'ax_si<e = 'ain_screen_turbines.'ax_si<e(); 0ote? any member functions described in the vector*section can be found among the rest of the ST, containers< too. The description applies to those containers accordingly and 6ill be referenced 6hen discussing these containers. STL Tutorial page 1& Johannes Weidl shape turbine horn pipe s6itch electrical s6itch mechanical s6itch si<e_type is an unsigned integral type< this could be for e5ample unsi!ne" lon!. The type that determines the si"e of the different containers is encapsulated by a type"e& to abstract from the actual memory model used. &or e5ampleH type"e& unsi!ne" lon! si<e_type; if the si"e is e5pressible by the built in type unsi!ne" lon!. ST, abstracts from the specific memory model used by a concept named allo!ators. All the information about the memory model is encapsulated in the Allocator class. 4ach container is templati"ed @parametri"edA by such an allo!ator to let the implementation be unchanged 6hen s6itching memory models. te'plate (class 5, te'plate (class H9 class Allocator = allocator9 class vector { ... }; The second template argument is a default argument that uses the pre*defined allocator GallocatorG< 6hen no other allocator is specified by the user. I 6ill describe allocators in detail in section ).3. If you 6ant to 8no6 the actual si"e of the vector * i.e. ho6 many elements it stores at the moment * you have to use the si<e() member functionH vector(turbine9 'ain_screen_turbines; vector(turbine9::si<e_type si<e = 'ain_screen_turbines.si<e(); cout (( )actual vector si<e: ) (( si<e; 0utputH a!t'al ve!tor si)e+ 9 ,i8e si<e_type describes the type used to e5press the si"e of a container< value_type gives you the type of the obBects that can be stored in itH vector(&loat9 v; cout (( )value type: ) (( typei" 1 (vector(&loat9::value_type).na'e(); 0utputH val'e type+ $loat A container turns out useless if no obBect can be inserted into or deleted from it. The vector< of course< provides member functions to do these Bobs and it does 9uite a bit moreH It is g'aranteed that inserting and erasing at the end of the vector ta8es amorti)ed constant time 6hereas inserting and erasing in the middle ta8es linear time. As stated in D$E< +*3< GIn several cases< the most useful characteri"ation of an algorithm=s computing time is neither 6orst case time nor average time< but amorti)ed time. D...E Amorti"ed time can be a useful 6ay to describe the time ta8en by an operation on some container in cases where the time !an vary widely as a se9uence of the operations is done< but the total time for a se9uence of 2 operations has a better bo'nd than Bust 2 times the 6orst* case time.G To understand this< remember that a vector is able to automatically e5pand its si"e. This e5pansion is done< 6hen an insert command is issued but no room is left in the storage allocated. In that case< ST, allocates room for #n elements @6here n is the actual si"e of the containerA and copies the n e5isting elements into the ne6 storage. This allocation and the copying process ta8e linear time. Then the ne6 element is inserted and for the ne5t n(. insertions only constant time is needed. So you need 0@nA time for n insertions< averaged over the n insert operations this results in 0@%A time for one insert operation. This more accurately reflects the cost of inserting than using the 6orst*case time 0@nA for each insert operation. % To use typei" include typein&o.h STL Tutorial page 1( Johannes Weidl 0f course amorti"ed constant time is about the same overhead as you have 6hen using (C(.. arrays but note that it is important to be about the same * and not more. &or the authors of ST, comple5ity considerations are very important because they are convinced that component programming and especially ST, 6ill only be accepted 6hen there is no @seriousA loss of efficiency 6hen using it. aybe there are users 6ho can afford to 6or8 inefficiently but 6ell designed * most can not. The follo6ing table sho6s the insert and erase overheads of the containers vector< list and "ePue. Thin8 of these overheads 6hen choosing a container for solving a specific tas8. Table 3: $nsert and erase over"eads for vector% list and deque -efore 6e loo8 at the insert functionality< there is another thing to consider. 1hen a vector is constructed using the default constructor @the default constructor is used 6hen no argument is given at the declarationA< no memory for elements is allocatedH vector(int9 v; 1e can chec8 this using the member function capacity(), 6hich sho6s the number of elements for 6hich memory has been allocatedH vector(int9::si<e_type capacity = v.capacity(); cout (( )capacity: ) (( capacity; 0utputH !apa!ity+ 9 At the first glance this doesn=t ma8e any sense but it gets clear 6hen you consider< that the vector class itself is able to allocate memory for the obBects inserted. In (.. you 6ould fill your turbine array as follo6sH turbine turb; turbine 'ain_screen_turbines ='ax_si<e>; 'ain_screen_turbines=0> = turb; In ST, you can use this synta5< tooH STL Tutorial page 2) Johannes Weidl Container insert$erase overhead at the beginning in the midd%e at the end Vector linear linear amorti"ed constant ,ist constant constant constant De9ue amorti"ed constant linear amorti"ed constant turbine turb; vector(turbine9 'ain_screen_turbines (10); EE allocate 'e'ory &or 10 EE ele'ents 'ain_screen_turbines=0> = turb; 2o6< 6e don=t use the default constructor but specify a number that tells the vector for ho6 many elements memory should be allocated. Then 6e use the overloaded subscribe operator @operator=> A to insert a turbine obBect into the vector. 0ote? If you use the subscribe operator 6ith an inde5< for 6hich no memory has been allocated @this is true for all indices 6hen declaring a vector 6ithout specifying a vector si"eA< the result 6ill be undefinedM To avoid memory allocation stuff the vector provides different member functions to insert elements into the vector. These insert functions do automatic memory allocation and * if necessary * e5pansion. To append an element at the end of a vector use push_bacL()H vector(int9 v; v.push_bacL (6); cout (( v.capacity() (( en"l; cout (( v=0>; 0utputH 19:; # < Three different @overloadedA 8inds of insert() member functions can be used. 7ere comes the firstH vector(int9 v; v.insert (v.en"(), 6); cout (( v.capacity() (( en"l; cout (( v=0>; 0utputH 19:; < This first 8ind of the insert() member function needs t6o argumentsH an iterator GpointingG to a definite container position and an element 6hich is to be inserted. The element is inserted before the specified iterator(position< that is before the element the specified iterator points to. The term iterator needs some e5planation. There are t6o member functions 6hich return so* called iteratorsH be!in() and en"(). Iterators are a generali"ation of the (.. pointers. An iterator is a 8ind of pointer but indeed more than a pointer. ,i8e a pointer is dereferenced by the e5pression =pointer< an iterator has the dereference operator defined 6hich returns a value of a specific type * the value type of the iterator. Additionally< li8e a pointer can be incremented by using the operatorJJ< an iterator can be incremented in the same 6ay. Iterators most often are associated 6ith a container. In that case< the value type of the iterator is the value type of the container and dereferencing the iterator returns an obBect of this value type. ,oo8 at this e5ample to get a feeling ho6 iterators behaveH # This value depends on the environment @memory modelA used STL Tutorial page 21 Johannes Weidl vector(int9 v(6); v=0> = 3; v=1> = +; v=+> = Q; vector(int9::iterator &irst = v.be!in(); vector(int9::iterator last = v.en"(); $hile (&irst 2= last) cout (( &irstJJ (( ) ); 0utputH , 1 > v.be!in() returns an iterator to the first element in the vector. The iterator can be dereferenced and incremented li8e a (.. pointer. Please note< that v.en"() doesn=t return an iterator that points to the last element in the vector * as no6 could be supposed * but past the last element @ho6ever< in the ST, code such an iterator is named lastA. Accordingly it is called past(the(end iterator. A user is not supposed to dereference such an iterator< because the result 6ould be undefined. The $hile loop chec8s if the &irst iterator is e9ual to the last iterator. If not< the iterator is dereferenced to get the obBect it is pointing to< then it is incremented. So< all vector elements are 6ritten to cout. Figure &: 'ange specified b# iterators A range =i, ;) given by the iterators i and ; is valid< if ; is rea!hable from i< that means if there is a finite se9uence of applications of operatorJJ to i that ma8es i==;T +anges given by t6o iterators are very important in ST,< because ST, algorithms largely 6or8 in the follo6ing 6ayH sort (be!inKiterator, past_the_en"Kiterator) 6here be!inKiterator specifies the first element in the range and past_the_en"Kiterator points past the last element of the range to be sorted. The range is correctly specified by the e5pression =be!inKiterator, past_the_en"K iterator). A valid sort command for our vector*e5ample 6ould beH STL Tutorial page 22 Johannes Weidl obBect of type val'e3type Andy !ohn Peter ary Tom iterator returned by member function begin() iterator returned by member function end() range Dbegin@A< end@A A sort 6 (v.be!in(), v.en"() ); Using iterators as intermediates< 6e are able to seperate the algorithms from the container implementationsH Figure (: )rt"ogonal decomposition of t"e component space After this short survey on iterators< 6hich 6ill be described in very detail in the ne5t section< 6e focus on the vector container again. 1e learned that specifying a number 6hen declaring a vector reserves memory for elements. Additionally to that< you can give the elements for 6hich memory is reserved an initial valueH vector(int9 v(6, 1Q); &or (int i = 0; i ( 6; iJJ) cout (( v=i> (( ) ); 0utputH .> .> .> It is possible to construct a vector out of another or to assign one vector to another vectorH vector(&loat9 v (3, 6.+3); vector(&loat9 v_ne$1 (v); EE construct v_ne$1 out o& v vector(&loat9 v_ne$+ = v; EE assi!n v to vne$+ vector(&loat9 v_ne$6 (v.be!in(), v.en"() ); EE construct v_ne$6 out o& the ele'ents o& v The last version uses iterators to specify the range out of 6hich the v_ne$6 vector should be constructed. The three v_ne$ * vectors are all e9ualH (v_ne$1 == v_ne$+) && (v_ne$+ == v_ne$6) && (v_ne$1 == v_ne$6) 8 M cout (( )ePual) : cout (( )"i&&erent); 0utputH e0'al To be able to compare vectors< an e9uality operator== for vectors is provided. To s6ap t6o vectors< a special member function is provided 6hich needs merely constant time< because only internal pointers are manipulated. vector(int9 v (1, 10); vector(int9 $ (1, +0); v.s$ap ($); cout (( v=0>; $ To use algorithms in your programs you have to include al!o.h STL Tutorial page 23 Johannes Weidl $ontainer ,l*orithm Iterator Iterator 0bBect 0utputH 19 1ith the member function e'pty() one can test if a vector is empty< i.e. if its si"e is "eroH vector(char9 v; v.e'pty() 8 cout (( )e'pty) : cout (( )not e'pty); 0utputH empty The first and the last element are returned 6hen invo8ing &ront() and bacL()H vector(int9 v (10, 3); v.push_bacL (Q); cout (( v.&ront() (( ) ) (( v.bacL(); 0utputH , > 1ith pop_bacL() the last element is returned and deleted from the vector. vector(int9 v (1, +); int value = v.pop_bacL (); cout (( value (( en"l; v.e'pty() 8 cout (( )e'pty) : cout (( )not e'pty); 0utputH 1 empty Additionally to the insert() member function that ta8es an iterator and an element as arguments< t6o more versions are providedH vector(int9 v; v.insert (v.be!in(), +, 3); EE vector v: 3 3 vector(int9 $ (1, 6); $.insert ($.en"(), v.be!in(), v.en"() ); EE vector $: 6 3 3 The second argument of the first version specifies ho6 many copies of an element * given as third argument * should be inserted before the specified iterator*position @first argumentA. The second version ta8es additionally to the inserting position $.en"() t6o iterators that specify the range 6hich is to be inserted. Using the erase() member function< it is possible to erase single elements or ranges @specified by t6o iteratorsA from a vector. Accordingly< there are t6o versions of erase(). 4rasing at the end of the vector ta8es constant time 6hereas erasing in the middle ta8es linear time. vector(&loat9 v (,, R.0); EE vector v: R.0 R.0 R.0 R.0 v.erase (v.be!in() ); EE vector v: R.0 R.0 R.0 v.erase (v.be!in(), v.en"() ); EE vector v: The first version erases the first vector element. The second version erases all remaining elements so the vector gets empty. 1hen inserting in or erasing from a container< there is something to ta8e into consideration. If you have an iterator pointing e.g. to the end of a vector and you insert an element at its beginning< the iterator to the end gets invalid. 0nly iterators before the insertion point remain valid. If no place is left and e5pansion ta8es place< all iterators get invalid. This is clear< because ne6 memory is allocated< the elements are copied and the old memory is freed. STL Tutorial page 24 Johannes Weidl Iterators aren=t automatically updated and get invalid< that means the result of operations using such iterators is undefined. Ta8e this into consideration 6hen inserting or erasing and then using iterators earlier defined on this container. The follo6ing table sho6s the validity of the containers vector< list and "ePue after inserting and erasing an element< respectively. Table 4: $terator validit# after inserting or erasing 2o6 6e are able to store obBects in a container @at least in the vectorA that provides several means to administer and maintain it. To apply algorithms to the elements in the vector 6e have to understand the iterator concept 6hich is described in detail in the ne5t section. 4.1.2 89ercises This section contains specifications for e5ercises dealing 6ith the topics in section ).%. Solving these tas8s should give you the possibility to apply your lections learned and compare your solutions 6ith the ones given in the solutions part of this tutorial. 7xer!ise :%.%.+ 1rite a ST, program that declares a vector of integer values< stores five arbitrary values in the vector and then prints the single vector elements to cout. -e sure to have read section $.$ on ho6 to compile ST, programs. 7xer!ise :%.%1+ 1rite a ST, program that ta8es an arbitrary se9uence of binary digits @integer values / and %A from cin and stores them into a container. 1hen receiving a value different from 0 or 1 from cin stop reading. 2o6< you should have a container storing a se9uence of 0=s and 1=s. After finishing the read*process< apply a Gbit*stuffingG algorithm to the container. -it*stuffing is used to transmit data from a sender to a receiver. To avoid bit se9uences in the data< 6hich 6ould erroneously be interpreted as the stop flag @hereH /%%%%%%/A< it is necessary to ensure that si5 consecutive 1=s in the data are splitted by inserting a 0 after each consecutive five 1=s. <int? (omple5ity considerations @inserting in the middle of a vector ta8es linear timeMA and the fact< that inserting into a vector can ma8e all iterators to elements invalid should ma8e you choose the ST, container list. A list of integers is defined li8e a vector by list(int9 l; All operations e5plained in the vector section are provided for the list< too. Get an iterator to the first list element. As long as this iterator is different from the en"() iterator increment the iterator and dereference it to get the appropriate binary value. 2ote that an element is al6ays inserted before a specified iterator*position and that this insertion doesn=t affect all the other iterators defined 6hen using a list. 7xer!ise :%.%<+ +efine 7xer!ise :%.%1 and print the original bit se9uence and the Gbit*stuffedG bit se9uence to cout. Use the hint from 7xer!ise :%.%1 to form a loop for the output procedure. 7xer!ise :%.%:+ +efine 7xer!ise :%.%< and print out the absolute and relative e5pansion of the bit se9uence. The absolute e5pansion is the e5pasion measured in bits @e.g. the bit*stuffed se9uence has increased by 3 bitsA< the relative e5pansion is the percentage of the e5pansion @e.g. the relative e5pansion bet6een the Gne6G and GoldG se9uence is 3.%#UA. STL Tutorial page 2 Johannes Weidl Container oeration iterator va%idit" vector inserting reallocation necessary * all iterators get invalid no reallocation * all iterators before insert point remain valid erasing all iterators after erasee point get invalid list inserting all iterators remain valid erasing only iterators to erased elements get invalid de9ue inserting all iterators get invalid erasing all iterators get invalid 7xer!ise :%.%,+ +efine 7xer!ise :%.%: and 6rite the inverse algorithm to the one in 7xer!ise :%.%1 that the receiver has to perform to get the initial binary data representation. After the bit*stuffing and bit*unstuffing compare your list 6ith the original one using the e9uality operator==. If the lists are e9ual< you did a fine Bob. 0ote? It is advisable to include a plausibility test in your unstuff algorithm. After a se9uence of five consecutive ones there must be a "ero< other6ise something 6ent 6rong in the stuffing algorithm. 4.2 Iterators GIterators are a generali"ation of pointers that allo6 a programmer to 6or8 6ith different data structures @containersA in a uniform mannerG< D#E. &rom the short survey in section ).%.% 6e 8no6 that iterators are obBects that have operator returning a value of a type called the val'e type of the iterator. Since iterators are a generali"ation of pointers it is assumed that every template function that ta8es iterators as arguments also 6or8s 6ith regular pointers. There are five categories of iterators. Iterators differ in the operations defined on them. 4ach iterator is designed to satis$y a 6ell*defined set of re9uirements. These re9uirements define 6hat operations can be applied to the iterator. According to these re9uirements the iterators can be assigned to the five categories. Iterator categories can be arranged from left to right to e5press that the iterator category on the left satisfies the re9uirements of all the iterator categories on the right @and so could be called more po6erfulA. Figure *: $terator categories STL Tutorial page 2! Johannes Weidl ?andom A!!ess Iterators @idire!tional Iterators Aorward Iterators &np't Iterators B'tp't Iterators means< iterator category on the left satisfies the re9uirements of all iterator categories on the right This arrangement means that a template function 6ich e5pects for e5ample a bidirectional iterator can be provided 6ith a random access iterator< but never 6ith a for6ard iterator. Imagine an algorithm that needs random access to fulfil his tas8< but is provided 6ith a method that only allo6s to pass through the elements successively from one to the ne5t. It simply 6on=t 6or8. Iterators that point past the last element of a range are called past(the(end iterators. Iterators for 6hich the operator is defined are called dere$eren!eable. It is never assumed that past*the*end iterators are dereferenceable. An iterator value @i.e. an iterator of a specific iterator typeA that isn=t associated 6ith a container is called sing'lar @iteratorA value. Pointers can also be singular. After the declaration of an uninitiali"ed pointer 6ith int x; x is assumed to be singular. Dereferenceable and past*the*end iterators are al6ays non(sing'lar. All the categories of iterators have only those functions defined that are reali"eable for that category in @amorti"edA constant time. This underlines the efficiency concern of the library. -ecause random access in a lin8ed list doesn=t ta8e constant time @but linear timeA< random access iterators cannot be used 6ith lists. 0nly inputCoutput iterators up to bidirectional iterators are valid for the use 6ith the container list. The follo6ing table sho6s the iterators that can be used 6ith the containers vector< list and "ePue @of course all iterators that satisfy the re9uirements of the listed iterators can be used as 6ellAH Container Iterator Categor" vector random access iterators list bidirectional iterators de9ue random access iterators Table &: +ost po,erful iterator categories t"at can be used ,it" vector% list and deque Iterators of these categories are returned 6hen using the member functions be!in or en" or declaring an iterator 6ith e.g. vector(int9::iterator i; The iterator categories 6ill be e5plained starting 6ith the input iterators and output iterators. 4.2.1 Input Iterators and 5utput Iterators An input iterator has the fe6est re9uirements. It has to be possible to declare an input iterator. It also has to provide a constructor. The assignment operator has to be defined< too. T6o input iterators have to be comparable for e9uality and ine9uality. operator has to be defined and it must be possible to increment an input iterator. Input Iterator +e9uirementsH constructor assignment operator e9ualityCine9uality operator dereference operator preCpost increment operator STL Tutorial page 2% Johannes Weidl 0utput iterators have to satisfy the follo6ing re9uirementsH 0utput Iterator +e9uirementsH constructor assignment operator dereference operator preCpost increment operator These abstract re9uirements should get clear if you loo8 at special input and output iterators provided by the library * the istream iterator and the ostream iterator. GTo ma8e it possible for algorithmic templates to 6or8 directly 6ith inputCoutput streams< appropriate iterator*li8e template classes are providedG< D#E. These template classes are named istrea'_iterator and ostrea'_iterator. Assume 6e have a file filled 6ith /=s and %=s. 1e 6ant to read the values from a file and 6rite them to cout. In (.. one 6ould 6riteH i&strea' , i&ile ()exa'ple_&ile)); int t'p; $hile (i&ile 99 t'p) cout 3 (( t'p; 0utput @e5ampleAH ..9.9...9...9.. 0ote? The /=s and %=s in the file have to be separated by whitespa!es @blan8< tab< ne6line< formfeed or carriage returnA. Using an istream and an ostream iterator in combination 6ith the algorithm copy enables us to 6rite the follo6ingH i&strea' i&ile ()exa'ple_&ile)); copy (istrea'_iterator 7 (int, ptr"i&&_t9 (i&ile), istrea'_iterator(int, ptr"i&&_t9 (), ostrea'_iterator(int9 (cout) ); The output 6ill be the same as in the above (.. e5ample. copy is an algorithm that ta8es t6o iterators to specify the range from 6hich elements are copied and a third iterator to specify the destination 6here the elements should be copied to. The template function loo8s as follo6sH te'plate (class @nput@terator, class /utput@terator9 /utput@terator copy (@nput@terator &irst, @nput@terator last, /utput@terator result); The template arguments have semantic meaning< they describe the iterator categories of that iterators provided to the function at least have to be. The iterators specifying the input range have to be at least input iterators< that means that it must be possible to increment and dereference them to get the appropriate values. The iterator specifying the result position has to be at least of the output iterator category. Since for6ard< bidirectional and random access iterators satisfy the re9uirements of input and output iterators< they can be used instead 6ith the same functionality. Dereferencing an output iterator has to result in a lval'e< that means it has to be possible to assign a value to the dereferenced output iterator @that is as you 8no6 an obBect of the value ) To use i&strea' include &strea'.h 3 To use streams li8e cin and cout and operator((< operator99 for streams include iostrea'.h : To use istrea'_iteator or ostrea'_iterator include iterator.h If you have to include al!o.h @as in this e5ampleA< iterator.h is already included by al!o.h STL Tutorial page 2& Johannes Weidl type of the iteratorA. &or output iterators< the only valid use of the operator is on the left side of the assignment statementH a is an output iterator, t is a value o& value type 5 a = t; vali" t = a; invali" &or output iterators< the three follo6ing conditions should holdH Assignment through the same value of the iterator should happen only once. ostrea'_iterator(int9 r (cout); r = 0; r = 1; is not a valid code se9uence. Any iterator value sould be assigned before it is incremented. ostrea'_iterator(int9 r (cout); rJJ; rJJ; is not a valid code se9uence. Any value of an output iterator may have at most one active copy at any given time. EE i an" ; are output iterators EE a an" b are values $ritten to a iterator position i = ;; iJJ = a; ; = b; is not a valid code se9uence. &or both input and output iterators algorithms 6or8ing on them are assumed to be single pass algorithms. Such algorithms are never assumed to attempt to pass the same iterator t6ice. &or input iterators r and s< r==s does not imply JJr == JJsH i&strea' i&ile ()exa'ple_&ile)) EE exa'ple_&ile: 0 1 + 6 istrea'_iterator(int, ptr"i&&_t9 r (i&ile); istrea'_iterator(int, ptr"i&&_t9 s (i&ile); (r==s) 8 cout (( )ePual) : cout (( )not ePual); cout (( en"l; JJr; JJs; cout (( r (( en"l; cout (( s (( en"l; (r==s) 8 cout (( )ePual) : cout (( )not ePual); cout (( en"l; 0utputH e0'al 1 < STL Tutorial page 2( Johannes Weidl e9ual 0ote? &or t6o input iterators a and b< a == b implies a == b. &or istream iterators< this condition doesnJt hold. 1hen incrementing an input iterator< a value is read from the input stream and stored temporarily in the input iterator obBect. Dereferencing the input iterator returns the value stored. The constructor of the istream iterator ta8es an input stream as its argument from 6hich values are read. To yield an end*of*stream iterator 6hich represents the end of file @C/DA of the input stream< the default constructor has to be used. To successfully construct an istream iterator< t6o template arguments have to be provided< too. The first argument specifies the type of the elements read from the input stream< the second is ptr"i&&_t< that is the type of the difference of t6o pointers in the actual memory model @see section ).3 * allocatorsA. The constructor of the ostream iterator can ta8e one or t6o arguments. 7o6ever< the first argument specifies the output stream to 6hich values are 6ritten. The alternative second argument is a string 6hich is printed bet6een the 6ritten values. ostrea'_iterator ta8es a template argument 6hich determines the type of the values 6ritten to the output stream. It 6ill often be as8ed to copy elements from an input stream @e.g. a fileA directly into a containerH vector(int9 v; i&strea' i&ile ()exa'ple_&ile)); copy (istrea'_iterator(int, ptr"i&&_t9 (i&ile), istrea'_iterator(int, ptr"i&&_t9 (), bacL_inserter(v) ); The function bacL_inserter returns a bacL_insert_iterator. This is a so*called iterator adaptor @e5plained in detail in section ).)A and is a 8ind of past*the*end iterator to the container. The container< for 6hich a bac8 insert iterator is to be created< has to be handed over to bacL_inserter. 1hen a value is 6ritten to the bac8 insert iterator< it is appended to the specified container as its last element. If< for e5ample< v.en"() is used instead of the bac8 insert iterator in the e5ample above< all the values inserted 6ill be 6ritten to the same vector position @v.en"()A< because v.en"() isnJt incremented after 6riting to it. This increment is internally done by the bac8 insert iterator by calling the container member function push_bacL. 4.2.2 "or,ard Iterators &or6ard iterators have to satisfy the follo6ing re9uirementsH STL Tutorial page 3) Johannes Weidl &or6ard Iterator +e9uirementsH constructor assignment operator e9ualityCine9uality operator dereference operator preCpost increment operator The difference to the input and output iterators is that for t6o for6ard iterators r and s< r==s implies JJr==JJs. A difference to the output iterators is that operator is also valid on the left side of the assignment operator @t = a is validA and that the number of assignments to a for6ard iterator is not restricted. So< m'lti(pass one(dire!tional algorithms can be implemented on containers that allo6 the use of for6ard iterators @loo8 at Table ,A. As an e5ample for a single*pass one*directional algorithm &in"_linear is presented. It iterates through the elements of a container and returns the iterator position 6here a value provided to &in"_linear is found< other6ise the past*the*end iterator is returned. The overhead of &in"_linear is statistically nC1. te'plate(class Dor$ar"@terator, class 59 Dor$ar"@terator &in"_linear (Dor$ar"@terator &irst, Dor$ar"@terator last, 5& value) { $hile (&irst 2= last) i& (&irstJJ == value) return &irst; return last; } vector(int9 v (6, 1); v.push_bacL (Q); EE vector v: 1 1 1 Q vector(int9::iterator i = &in"_linear (v.be!in(), v.en"(), Q); i& (i 2= v.en"() ) cout (( i; else cout (( )not &oun"); 0utputH > 4.2.3 3idirectional Iterators In addition to for6ard iterators< bidirectional iterators satisfy the follo6ing re9uirementsH -idirectional Iterator +e9uirements @additional to for6ard iterators=AH preCpost decrement operator -idirectional iterators allo6 algorithms to pass through the elements for6ard and bac86ard. list(int9 l (1, 1); l.push_bacL (+); EE list l: 1 + list(int9::iterator &irst = l.be!in(); list(int9::iterator last = l.en"(); $hile (last 2= &irst) { KKlast; cout (( last (( ) ); } 0utputH 1 . STL Tutorial page 31 Johannes Weidl The bubble sort algorithm serves as an e5ample for a multi*pass algorithm using bidirectional iterators. te'plate (class Ii"irectional@terator, class .o'pare9 voi" bubble_sort (Ii"irectional@terator &irst, Ii"irectional@terator last, .o'pare co'p) { Ii"irectional@terator le&t_el = &irst, ri!ht_el = &irst; ri!ht_elJJ; $hile (&irst 2= last) { $hile (ri!ht_el 2= last) { i& (co'p(ri!ht_el, le&t_el)) iter_s$ap (le&t_el, ri!ht_el); ri!ht_elJJ; le&t_elJJ; } lastKK; le&t_el = &irst, ri!ht_el = &irst; ri!ht_elJJ; } } The binary function obBect .o'pare has to be provided by the user of bubble_sort. .o'pare< 6hich implements a binary predicate< ta8es t6o arguments and returns the result @true or &alseA of the predicate provided 6ith the t6o arguments. list(int9 l; EE &ill list bubble_sort (l.be!in(), l.en"(), less(int9() ); EE sort ascen"in!ly bubble_sort (l.be!in(), l.en"(), !reater(int9() );EE sort "escen"in!ly 4.2.4 1ando$ *ccess Iterators In addition to bidirectional iterators< random access iterators satisfy the follo6ing re9uirementsH +andom Access Iterator +e9uirements @additional to bidirectional iterators=AH operator. @intA operator.V @intA operator* @intA operator*V @intA operator* @random access iteratorA operatorDE @intA operator Q @random access iteratorA operator R @random access iteratorA operator RV @random access iteratorA operator QV @random access iteratorA +andom access iterators allo6 algorithms to have random access to elements stored in a container 6hich has to provide random access iterators< li8e the vector. STL Tutorial page 32 Johannes Weidl vector(int9 v (1, 1); v.push_bacL (+); v.push_bacL (6); v.push_bacL (,); EE vector v: 1 + 6 , vector(int9::iterator i = v.be!in(); vector(int9::iterator ; = i J +; cout (( ; (( ) ); i J= 6; cout (( i (( ) ); ; = i K 1; cout (( ; (( ) ); ; K= +; cout (( ; (( ) ); cout (( v=1> (( en"l; (; ( i) 8 cout (( ); ( i) : cout (( )not (; ( i)); cout (( en"l; (; 9 i) 8 cout (( ); 9 i) : cout (( )not (; 9 i)); cout (( en"l; i = ;; i (= ; && ; (= i 8 cout (( )i an" ; ePual) : cout (( )i an" ; not ePual); cout (( en"l; ; = v.be!in(); i = v.en"(); cout (( )iterator "istance en" K be!in =S si<e: ) (( (i K ;); 0utputH < : < . 1 * 2 i not (i 4 *) i and * e0'al iterator distan!e end ( begin DE si)e+ : An algorithm that needs random access to container elements to 6or8 6ith 0@ld nA is the binary search algorithm. In section ).$ algorithms and function obBects are e5plained and it is sho6n ho6 they 6or8 together in a very advantageous 6ay. 4.2. 89ercises 7xer!ise :%1%.+ +efine 7xer!ise :%.%, by reading the original bit se9uence out of a user built file bit3se0. Additionally< store the bit*stuffed bit se9uence in the file bit3st$$ @note that the integer values in the input and output stream have to be separated by 6hitespacesA. <int? The output file bit3st$$ has to be declared as o&strea'< 6hich is defined li8e i&strea' in &strea'.h. 4.3 *lgorith$s and "unction 5b#ects All the algorithms provided by the library are parametri"ed by iterator types and are so seperated from particular implementations of data structures. -ecause of that they are called generi! algorithms. 4.3.1 :o, to create a generic algorith$ I 6ant to evolve a generic binary sear!h algorithm out of a conventional one. The starting point is a (.. binary search algorithm 6hich ta8es an integer array< the number of elements in the array and the value searched for as arguments. binary_search returns a constant pointer to the element * if found * the nil pointer else. STL Tutorial page 33 Johannes Weidl const int binary_search (const int array, int n, int x) { const int lo = array, hi = array J n, 'i"; $hile(lo 2= hi) { 'i" = lo J (hi K lo) E +; i& (x == 'i") return 'i"; i& (x ( 'i") hi = 'i"; else lo = 'i" J 1; } return 0; } ,et us loo8 at the assumptions this algorithm ma8es about its environment. binary_search only 6or8s 6ith integer arrays. To ma8e it 6or8 6ith arrays of arbitrary types 6e transform binary_search in a template function. te'plate(class 59 const 5 binary_search (const 5 array, int n, const 5& x) { const 5 lo = array, hi = array J n, 'i"; $hile(lo 2= hi) { 'i" = lo J (hi K lo) E +; i& (x == 'i") return 'i"; i& (x ( 'i") hi = 'i"; else lo = 'i" J 1; } return 0; } 2o6 the algorithm is designed for use 6ith arrays of different types. In case of not finding the value searched for< a special pointer * nil * is returned. This re9uires that such a value e5ists. Since 6e don=t 6ant to ma8e this assumption< in case of an unsuccessful search 6e return the pointer array J n @yes< a past*the*end pointerA instead. te'plate(class 59 const 5 binary_search (const 5 array, int n, const 5& x) { const 5 lo = array, hi = array J n, 'i"; $hile(lo 2= hi) { 'i" = lo J (hi K lo) E +; i& (x == 'i") return 'i"; i& (x ( 'i") hi = 'i"; else lo = 'i" J 1; } return array J n; } Instead of handing over array as pointer to the first element and a si"e< 6e could also specify a pointer to the first and past the last element to approach ST,=s iterator concept. te'plate(class 59 const 5 binary_search (5 &irst, 5 last, const 5& value) { const 5 lo = array, hi = array J n, 'i"; $hile(lo 2= hi) { 'i" = lo J (hi K lo) E +; i& (value == 'i") return 'i"; i& (value ( 'i") hi = 'i"; else lo = 'i" J 1; } return last; } To specify a pointer to the end of a container instead of handing over its si"e has the advantage that it has not to be possible to compute last out of &irst 6ith &irstJn. This is important for containers that don=t allo6 random access to their elements. -ecause our STL Tutorial page 34 Johannes Weidl binary_search needs random access to the elements of the container< this is of little importance in our e5ample. Another advantage is that the di$$eren!e type @here intA doesn=t have to be e5plicitly handed over< so the user of binary_search doesn=t even have to 8no6 it. The difference type is the type 6hich is used to e5press the type of the difference of t6o arbitrary iterators @pointersA< for e5ample last * &irst could be of the type si!ne" lon!. The last step to fully adapt the algorithm to the ST, style is to change the first and last pointer type from pointers to the value type to an appropriate iterator type. -y this step< the information of ho6 the algorithm steps from one element to the ne5t is torn a6ay from the algorithm implementation and is hidden in the iterator obBects. 2o6< no assumptions about the mechanism to iterate through the elements are made. This mechanism is handed over to the algorithm by the iterator obBects. So< the algorithm is separated from the container it 6or8s on< all the operations that deal 6ith iterators are provided by the iterator obBects themselves. Since binary_search needs random access to the elements of the container it is called for and so iterators handed over to binary_search have to satisfy the re9uirements of random access iterators< 6e name the type of &irst and last GNan"o'Access@teratorGH te'plate(class Nan"o'Access@terator, class 59 Nan"o'Access@terator binary_search (Nan"o'Access@terator &irst, Nan"o'Access@terator last, const 5& value) { Nan"o'Access@terator not_&oun" = last, 'i"; $hile(&irst 2= last) { 'i" = &irst J (last K &irst) E +; i& (value == 'i") return 'i"; i& (value ( 'i") last = 'i"; else &irst = 'i" J 1; } return not_&oun"; } The only assumptions the algorithm ma8es are the random access to elements of type 5 bet6een the t6o iterators @pointersA &irst and last and that operator== and operator( are defined for type 5 and the value type of the iterator. This generic binary search algorithm hasn=t lost anything of its functionality< especially not 6hen dealing 6ith built in types. int x=10>; EE array o& ten inte!er values int search_value; EE value searche" &or EE initiali<e variables int i = binary_search (&x=0>, &x=10>, search_value); i& (i == &x=10>) cout (( )value not &oun"); else cout (( )value &oun"); All the ST, algorithms are constructed li8e our e5ample algorithm * they try to ma8e as fe6 assumptions as possible about the environment they are run in. STL Tutorial page 3 Johannes Weidl 4.3.2 The STL algorith$s The algorithms delivered 6ith the library are divided into four groupsH grou a%gorithm t"e % mutating se9uence operations # non*mutating se9uence operations $ sorting and related operations ) generali"ed numeric operations Table (: STL algorit"m t#pes Group % contains algorithms 6hich don=t change @mutateA the order of the elements in a container< this has not to be true for algorithms of group #. The algorithm &or_each of group % ta8es t6o iterators and a function & of type Dunction as argumentsH te'plate (class @nput@terator, class Dunction9 Dunction &or_each (@nput@terator &irst, @nput@terator last, Dunction &); The template argument & of type Dunction must not be mi5ed up 6ith a GpureG (.. function< because such a function can only be used in a roundabout 6ay @see section ).).$A. The template function &or_each e5pects a $'n!tion ob*e!t @section #.#A as argument. & is assumed not to apply any non*constant function through the dereferenced iterator. &or_each applies f to the result of dereferencing every iterator in the range =&irst, last) and returns &. If & returns a value< it is ignored. The follo6ing e5ample computes the sum of all elements in the range =&irst, last). te'plate (class 59 class su'_up { public: voi" operator() (const 5& value) { su' J= value; } const 5& rea"_su'() { return su'; } private: static 5 su'; }; int su'_up(int9::su'; voi" 'ain(voi") { "ePue Q (int9 " (6,+); su'_up(int9 s; &or_each (".be!in(), ".en"(), s); cout (( s.rea"_su'(); } 0utputH F Group % also contains an algorithm &in"< 6hich is very similar to &in"_linear from section ).#.#. ; To use a "ePue include "ePue.h STL Tutorial page 3! Johannes Weidl te'plate (class @nput@terator, class 59 @nput@terator &in"(@nput@terator &irst, @nput@terator last, const 5& value); &in" ta8es a range and a reference to a value of arbitrary type. It assumes that operator== for the value type of the iterator and 5 is defined. Additionally to &in" an algorithm named &in"_i& is provided< 6hich ta8es a predicate pre" of type Tre"icate. te'plate (class @nput@terator, class Tre"icate9 @nput@terator &in"_i&(@nput@terator &irst, @nput@terator last, Tre"icate pre"); &in"_i& @li8e &in"A returns the first iterator i in the range =&irst, last)< for 6hich the follo6ing condition holdsH pre"(i) = true. If such an iterator doesn=t e5ist< a past*the end iterator is returned. te'plate (class 59 class &in"_&irst_!reater { public: &in"_&irst_!reater() : x(0) {} &in"_&irst_!reater(const& xx) : x(xx) {} int operator() (const 5& v) { return v 9 x; } private: 5 x; }; vector(int9 v; EE &ill vector $ith 1 + 6 , 3 vector(int9::iterator i = &in"_i& (v.be!in(), v.en"(), &in"_&irst_!reater(int9 (6)); i 2= v.en"()8 cout (( i : cout (( )not &oun"); 0utputH : Generally< if there is a version of an algorithm 6hich ta8es a predicate< it gets the name of the algorithm 6ith the suffi5 _i&. Some algorithms< li8e a";acent_&in"< ta8e a binary predicate binary_pre" of type IinaryTre"icate. a";acent_&in" returns the first iterator i< for 6hich the follo6ing condition holdsH binary_pre" (i, (iJ1)) == true. te'plate (class @nput@terator, class IinaryTre"icate9 @nput@terator a";acent_&in"(@nput@terator &irst, @nput@terator last, IinaryTre"icate binary_pre"); &or e5ample< if you 6ant to find the first pair of values< 6hose product is odd< you could 6rite thisH te'plate (class 59 class pro"_o"" { public: int operator() (const 5& v1, const 5& v+) { return v1U+ 2= 0 && v+U+ 2= 0; } }; list(int9 l; EE &ill list $ith + 4 7 16 Q list(int9::iterator i = a";acent_&in" (l.be!in(), l.en"(), pro"_o""(int9()); i& (i 2= l.en"()) { cout (( i (( ) ); iJJ; cout (( iJJ; } else cout (( )not &oun"); STL Tutorial page 3% Johannes Weidl 0utputH .< > Algorithms can 6or8 in pla!e< that means they do their 6or8 6ithin the specified range. Some algorithms have an additional version 6hich copies 6ell*defined elements to an output iterator result. 1hen such a version is provided< the algorithm gets the suffi5 _copy @6hich precedes a probable suffi5 _i&A. &or e5ample there is replace_copy_i&< 6hich assigns to every iterator in the range =result, resultJ(lastK&irst) ) either a ne6 value @6hich has to be specifiedA or the original value. This depends on a predicate given as argument. te'plate (class @terator, class /utput@terator, class Tre"icate, class 59 /utput@terator replace_copy_i&(@terator &irst, @terator last, /utput@terator result, Tre"icate pre", const 5& ne$_value); All the operations in group $ have t6o versions. 0ne that ta8es a function obBect co'p of type .o'pare and another that uses operator( to do the comparison. operator( and co'p< respectively< have to induce a total ordering relation on the values to ensure that the algorithms 6or8 correctly. vector(int9 v; EE &ill v $ith 6 Q 3 , + 7 sort (v.be!in(), v.en"() ); sort (v.be!in(), v.en"(), less(int9() ); sort (v.be!in(), v.en"(), !reater(int9() ); 0utputH 1 < : , F > 1 < : , F > > F , : < 1 Since the library provides function obBects for all of the comparison operators in the language 6e can use less to sort the container ascendingly and !reater to sort it descendingly. All the provided function obBects are derived either from unary_&unction or from binary_&unction to simplify the type definitions of the argument and result types. te'plate (class Ar!, class Nesult9 struct unary_&unction { type"e& Ar! ar!u'ent_type; type"e& Nesult result_type; }; te'plate (class Ar!1, class Ar!+, class Nesult9 struct binary_&unction { type"e& Ar!1 &irst_ar!u'ent_type; type"e& Ar!+ secon"_ar!u'ent_type; type"e& Nesult result_type; }; ST, provides function obBects for all of the arithmetic operations in the language. plus< 'inus< ti'es< "ivi"es and 'o"ulus are binary operations 6hereas ne!ate is a unary operation. As e5amples< loo8 at plus and ne!ate< the other functions obBects are defined accordingly. te'plate (class 59 struct plus : binary_&unction(5, 5, 59 { 5 operator()(const 5& x, const 5& y) const { return x J y; } }; te'plate (class 59 struct ne!ate : unary_&unction(5, 59 { STL Tutorial page 3& Johannes Weidl 5 operator()(const 5& x) const { return Kx; } }; The mentioned comparison function obBects are ePual_to< not_ePual_to< !reater< less< !reater_ePual and less_ePual< they are all binary function obBects. less shall serve as e5ample. te'plate (class 59 struct less : binary_&unction(5, 5, bool9 { bool operator()(const 5& x, const 5& y) const { return x ( y; } }; Additionally< the binary function obBects lo!ical_an" and lo!ical_or e5ist< lo!ical_not is a unary function obBect. te'plate (class 59 struct lo!ical_an" : binary_&unction(5, 5, bool9 { bool operator()(const 5& x, const 5& y) const { return x && y; } }; te'plate (class 59 struct lo!ical_not : unary_&unction(5, bool9 { bool operator()(const 5& x) const { return 2x; } }; The rest of the function obBect implementations can be found in D#E< :. In group )< the algorithm accu'ulate ta8es a binary operation binary_op of type Iinary/peration. The algorithm accu'ulate does the same as &or_each used 6ith the function obBect su'_up @presented earlier in this sectionA. te'plate (class @nput@terator, class 59 5 accu'ulate(@nput@terator &irst, @nput@terator last, 5 init); &or each iterator i in =&irst, last)< acc = acc J i is computed< then acc is returned. acc can be initiali"ed 6ith a starting value. Instead of operatorJ< an arbitrary binary operation can be defined by the user< or a ST, function obBect can be used. vector(int9 v; v.push_bacL (+); v.push_bacL (3); cout (( accu'ulate (v.be!in(), v.en"(), 10, "ivi"es(int9() ); 0utputH . I 6ant to present an e5ample 6hich implements a spell*chec8er. &or this purpose 6e assume the follo6ingH The dictionary is stored in a file The te5t to chec8 is stored in a file The 6ords of the te5t should be chec8ed against dictionary 4very 6ord not found or misspelled should be displayed 1e decide to use a non*associative container @see section ).%< introductionA< 6hich holds the dictionary. The dictionary is assumed to be sorted. 2o6< 6e e5press the spell*chec8er functionality in pseudo code. &or every $or" in text checL a!ainst "ictionary i& not in "ictionary $rite to output STL Tutorial page 3( Johannes Weidl This pseudo code can be e5pressed in different 6ayH copy every $or" o& text to output that is not in the "ictionary The last pseudo code variation can more directly be translated into a ST, program. Since 6e need a mechanism that tells us if a 6ord is or is not in the dictionary< 6e encapsulate this functionality in a function obBect. te'plate (class bi"irectional_iterator, class 59 class nonAssocDin"er { public: nonAssocDin"er(bi"irectional_iterator be!in, bi"irectional_iterator en") : _be!in(be!in), _en"(en") {} bool operator() (const 5& $or") { return binary_search(_be!in, _en", $or"); } private: bi"irectional_iterator _be!in; bi"irectional_iterator _en"; }; The function obBect nonAssocDin"er is initiali"ed 6ith the iterators be!in and en" that have to be at least of the bidirectional iterator category. The function call operator ta8es a 6ord and returns a boolean value< 6hich states if the 6ord has been found in the dictionary @the type bool is defined by ST,A. This boolean value is returned by the ST, algorithm binary_search. te'plate (class Dor$ar"@terator, class 59 bool binary_search(Dor$ar"@terator &irst, Dor$ar"@terator last, const 5& value); The first thing 6e do in our program is to define a dictionary as a vector of type strin! and fill it out of an input stream. type"e& vector(strin! R 9 "ict_type; i&strea' "ictDile()"ict.txt)); i&strea' $or"sDile()$or"s.txt)); "ict_type "ictionary; copy (istrea'_iterator(strin!, ptr"i&&_t9("ictDile), istrea'_iterator(strin!, ptr"i&&_t9(), bacL_inserter("ictionary)); ? To use the strin! type include cstrin!.h STL Tutorial page 4) Johannes Weidl Then 6e use the ST, algorithm re'ove_copy_i& to achieve the functionality 6anted. te'plate (class @nput@terator, class /utput@terator, class Tre"icate9 /utput@terator re'ove_copy_i&(@nput@terator &irst, @nput@terator last, /utput@terator result, Tre"icate pre"); re'ove_copy_i& 6rites all elements referred to by the iterator i in the range =&irst, last) to the output iterator result< for 6hich the follo6ing condition does not holdH pre"(i) == true. The algorithm returns the end of the resulting range. The rest of the spell*chec8er program proves to be a single statement. re'ove_copy_i& ( istrea'_iterator(strin!, ptr"i&&_t9($or"sDile), istrea'_iterator(strin!, ptr"i&&_t9(), ostrea'_iterator(strin!9(cout, )Mn)), nonAssocDin"er("ict_type::iterator, "ict_type::value_type9 ("ictionary.be!in(), "ictionary.en"())); re'ove_copy_i& reads 6ords from the input stream $or"sDile and 6rites the 6ords for 6hich nonAssocDin"er returns &alse @i.e. 6hich are either not found or misspelledA to cout. The components used areH algorithmsH copy and re'ove_copy_i& containerH vector user definedH function obBect nonAssocDin"er 2o6 you should have the basics to understand the chapter on algorithms in D#E< %/. Since this document is very theoretical< the algorithms in combination 6ith a description and e5amples can be found in D)E< :. A complete ST, e5ample can be found in D)E< 3. 4.3.3 89ercises 7xer!ise :%<%.+ &ill t6o containers 6ith the same number of integer values. (reate a ne6 container< 6hose elements are the sum of the appropriate elements in the original container. <int? The library provides an algorithm and a function obBect to do the e5ercise. 7xer!ise :%<%1+ 1rite a generator obBect 6hich can be used 6ith the ST, algorithm !enerate @group #A to fill containers 6ith certain values. It should be possible to specify a starting value and a step si"e< so that the first element in the container is the starting value and every further element is the sum of the preceding element and the step si"e. 4.4 *daptors As stated in D#E< %%< GAdaptors are template classes that provide interface mappingsG. Adaptors are classes that are based on other classes to implement a ne6 functionality. ember functions can be added or hidden or can be combined to achieve ne6 functionality. STL Tutorial page 41 Johannes Weidl 4.4.1 Container *daptors Stack. A stac8 can be instantiated either 6ith a vector< a list or a "ePue. The member functions e'pty< si<e< top< push and pop are accessible to the user. stacL 4 (vector(int9 9 s1; stacL(list(int9 9 s+; stacL("ePue(int9 9 s6; s1.push(1); s1.push(3); cout (( s1.top() (( en"l; s1.pop(); cout (( s1.si<e() (( en"l; s1.e'pty()8 cout (( )e'pty) : cout (( )not e'pty); 0utputH , . not empty top returns the element on the top of the stac8< pop removes the top element from the stac8. &or comparison of t6o stac8s< operator== and operator( are defined. @ueue. A 9ueue can be instantiated 6ith a list or a "ePue. Pueue(list(int9 9 P1; Pueue("ePue(int9 9 P+; Its public member functions are e'pty< si<e< &ront< bacL< push and pop. &ront returns the ne5t element from the 9ueue< pop removes this element. bacL returns the last element pushed to the 9ueue 6ith push. As 6ith the stac8< t6o 9ueues can be compared using operator== and operator(. 9riority =ueue. A priority 9ueue can be instantiated 6ith a vector or a "ePue. A priority 9ueue holds the elements added by push sorted by using a function obBect co'p of type .o'pare. EE use less as co'pare ob;ect priority_Pueue(vector(int9, less(int9 9 pP1; EE use !reater as co'pare ob;ect priority_Pueue("ePue(int9, !reater(int9 9 pP+; vector v(6, 1); EE create a priority_Pueue out o& a vector, use less as co'pare ob;ect priority_Pueue("ePue(int9, less(int9 9 pP6 (v.be!in(), v.en"() ); top returns the element 6ith the highest priority< pop removes this element. The element 6ith the highest priority is determined by the sorting order imposed by co'p. 2ote< that a priority 9ueue internally is implemented using a heap. So< 6hen less is used as compare obBect< the element 6ith the highest priority h 6ill be one of the elements for 6hich the follo6ing condition holdsH less (h, x) == &alse for all elements x in the priority 9ueue. Additionally< the member functions e'pty and si<e are provided. 2ote that no comparison operators for priority 9ueues are provided. &or the implementations of the container adaptors< read D#E< %%.%. 4.4.2 Iterator *daptors > To use a stacL < Pueue or priority_Pueue include stacL.h STL Tutorial page 42 Johannes Weidl Ae(er"e +terator". &or the bidirectional and random access iterators corresponding reverse iterator adaptors that iterate through a data structure in the opposite direction are provided. list(int9 l; EE &ill l $ith 1 + 6 , reverse_bi"irectional_iterator 10 (list(int9::iterator, list(int9::value_type, list(int9::re&erence_type, list(int9::"i&&erence_type9 r (l.en"()); cout (( r (( ) ); rJJ; cout (( r (( ) ); r KK; cout (( r; 0utputH : < : list(int9 l; EE &ill l $ith 1 + 6 , copy (reverse_iterator(int, int, int&, ptr"i&&_t9 (l.en"()), reverse_iterator(int, int, int&, ptr"i&&_t9 (l.be!in()), ostrea'_iterator(int9 (cout, ) )) ); 0utputH : < 1 . &or all the se9uence containers @vector< list and "ePueA the member functions rbe!in and ren" are provided< 6hich return the appropriate reverse iterators. list(int9 l; EE &ill l $ith 1 + 6 , copy (l.rbe!in(), l.ren"(), ostrea'_iterator(int9 (cout, ) ))); 0utputH : < 1 . +n"ert +terator". A 8ind of iterator adaptors< called insert iterators< simplify the insertion into containers. The principle is that 6riting a value to an insert iterator inserts this value into the container out of 6hich the insert iterator 6as constructed. To define the position< 6here the value is inserted< three different insert iterator adaptors are providedH bacL_insert_iterator &ront_insert_iterator insert_iterator bacL_insert_iterator and &ront_insert_iterator are constructed out of a container and insert elements at the end and at the beginning of this container< respectively. A bacL_insert iterator re9uires the container out of 6hich it is constructed to have push_bacL defined< a &ront_insert_iterator correspondingly re9uires push_&ront. "ePue(int9 "; bacL_insert_iterator("ePue(int9 9 bi ("); &ront_insert_iterator("ePue(int9 9 &i ("); insert_iterator is constructed out of a container and an iterator i< before 6hich the values 6ritten to the insert iterator are inserted. "ePue(int9 "; %/ To use reverse_bi"irectional_iterator or reverse_iterator include iterator.h STL Tutorial page 43 Johannes Weidl insert_iterator("ePue(int9 9 i (", ".en"() ); Insert iterators satisfy the re9uirements of output iterators< that means that an insert iterator can al6ays be used 6hen an output iterator is re9uired. operator returns the insert iterator itself. The three functions bacL_inserter< &ront_inserter and inserter return the appropriate insert iterators. te'plate (class .ontainer9 bacL_insert_iterator(.ontainer9 bacL_inserter(.ontainer& x) { return bacL_insert_iterator(.ontainer9(x); } te'plate (class .ontainer9 &ront_insert_iterator(.ontainer9 &ront_inserter(.ontainer& x) { return &ront_insert_iterator(.ontainer9(x); } te'plate (class .ontainer, class @terator9 insert_iterator(.ontainer9 inserter(.ontainer& x, @terator i) { return insert_iterator(.ontainer9(x, .ontainer::iterator(i)); } i&strea' & ()exa'ple)); EE &ile exa'ple: 1 6 "ePue(int9 "; copy (istrea'_iterator(int, ptr"i&&_t9(&), istrea'_iterator(int, ptr"i&&_t9(), bacL_inserter(") ); vector(int9 $ (+,Q); copy ($.be!in(), $.en"(), &ront_inserter (") ); insert_iterator("ePue(int9 9 i = inserter (", JJ".be!in() ); i = 4; 0uptutH > - > . < Aa: Stora*e +terator. A ra$_stora!e_iterator enables algorithms to store results into uninitiali"ed memory. vector(int9 a (+, 3); vector(int9 b (+, Q); int c = allocate((ptr"i&&_t) a.si<e(), (int)0 ); trans&or' ( a.be!in(), a.en"(), b.be!in(), ra$_stora!e_iterator(int, int9 (c), plus(int9() ); copy (&c=0>, &c=+>, ostrea'_iterator(int9 (cout, ) )) ); 0utputH .1 .1 The function allocate is provided by the ST, allocator @see ).3A< trans&or' is an algorithm of group # @see ).$.#A. To use a ra6 storage iterator for a given type 5< a construct function must be defined< 6hich puts results directly into uninitiali"ed memory by calling the appropriate copy constructor. The follo6ing construct function is provided by ST,H STL Tutorial page 44 Johannes Weidl te'plate (class 51, class 5+9 inline voi" construct(51 p, const 5+& value) { ne$ (p) 51(value); } int a=10> = {1, +, 6, ,, 3}; copy (&a=0>, &a=3>, ra$_stora!e_iterator(int, int9 (&a=3>) ); 4.4.3 "unction *daptors 0e*ator". The negators not1 and not+ are functions 6hich ta8e a unary and a binary predicate< respectively< and return their complements. te'plate (class Tre"icate9 unary_ne!ate(Tre"icate9 not1(const Tre"icate& pre") { return unary_ne!ate(Tre"icate9(pre"); } te'plate (class Tre"icate9 binary_ne!ate(Tre"icate9 not+(const Tre"icate& pre") { return binary_ne!ate(Tre"icate9(pre"); } The classes unary_ne!ate and binary_ne!ate only 6or8 6ith function obBect classes 6hich have argument types and result type defined. That means< that Tre"icate::ar!u'ent_type and Tre"icate::result_type for unary function obBects and Tre"icate::&irst_ar!u'ent_type< Tre"icate::secon"_ar!u'ent_type and Tre"icate::result_type for binary function obBects must be accessible to instantiate the negator classes. vector(int9 v; EE &ill v $ith 1 + 6 , sort (v.be!in(), v.en"(), not+ (less_ePual(int9()) ); 0utputH : < 1 . Binder". GThe binders bin"1st and bin"+n" ta8e a function obBect & of t6o arguments and a value x and return a function obBect of one argument constructed out of & 6ith the first or second argument correspondingly bound to x.G< D#E<%%.$.#. Imagine that there is a container and you 6ant to replace all elements less than a certain bound 6ith this bound. vector(int9 v; EE &ill v $ith , 7 10 6 16 + int boun" = 3; replace_i& (v.be!in(), v.en"(), bin"+n" (less(int9(), boun"), boun"); EE v: 3 7 10 3 16 3 bin"+n" returns a unary function obBect less that ta8es only one argument< because the second argument has previously been bound to the value boun". 1hen the function obBect is applied to a dereferenced iterator i< the comparison i ( boun" is done by the function*call operator of less. ,daptor" for pointer" to function". The ST, algorithms and adaptors are designed to ta8e function obBects as arguments. If a usual (.. function shall be used< it has to be 6rapped in a function obBect. STL Tutorial page 4 Johannes Weidl The function ptr_&un ta8es a unary or a binary function and returns the corresponding function obBect. The function*call operator of these function obBects simply calls the function 6ith the arguments provided. &or e5ample< if a vector of character pointers is to be sorted le5icographically 6ith respect to the character arrays pointed to< the binary (.. function strc'p can be transformed into a comparison obBect and can so be used for sorting. vector(char9 v; char c1 = ne$ char=+0>; strcpy (c1, )5i')); char c+ = ne$ char=+0>; strcpy (c+, ).harles)); char c6 = ne$ char=+0>; strcpy (c6, )Aaron)); v.push_bacL (c1); v.push_bacL (c+); v.push_bacL (c6); sort (v.be!in(), v.en"(), ptr_&un (strc'p) ); copy (v.be!in(), v.en"(), ostrea'_iterator(char9 (cout, ) )) ); 0utputH Aaron Charles Tim 0ote? The above e5ample causes memory lea8s< because the memory allocated 6ith ne$ is not automatically deallocated. See section ).3 for a solution. 4. *llocators and $e$or- handling G0ne of the common problems in portability is to be able to encapsulate the information about the memory model.G< D#E< ;. This information includes the 8no6ledge of pointer types type of their difference @difference type ptr"i&&_tA type of the si"e of obBects in a memory model @si"e type si<e_tA memory allocation and deallocation primitives. ST, provides allocators 6hich are obBects that encapsulate the above information. As mentioned in section ).%.%< all the ST, containers are parametri"ed in terms of allocators. So< containers donJt have any memory model information coded inherently but are provided 6ith this information by ta8ing an allocator obBect as argument. The idea is that changing memory models is as simple as changing allocator obBects. The allocator allocator< 6hich is defined in "e&alloc.h< is used as default allocator obBect. The compiler vendors are e5pected to provide allocators for the memory models supported by their product. So< for -orland (.. allocators for different memory models are provided @see $.#A. &or every memory model there are corresponding allocate< "eallocate< construct and "estroy template functions defined. allocate returns a pointer of type 5 to an allocated buffer< 6hich is no less than nsi<eo&(5). te'plate (class 59 inline 5 allocate(ptr"i&&_t si<e, 5); "eallocate frees the buffer allocated by allocate. te'plate (class 59 inline voi" "eallocate(5 bu&&er); STL Tutorial page 4! Johannes Weidl construct puts results directly into uninitiali"ed memory by calling the appropriate copy constructor. te'plate (class 51, class 5+9 inline voi" construct(51 p, const 5+& value) { ne$ (p) 51(value); } "estroy calls the destructor for a specified pointer. te'plate (class 59 inline voi" "estroy(5 pointer) { pointerK9V5(); } If you have a container of pointers to certain obBects< the container destructor calls a special destroy function to call all the single pointer destructors and free the memory allocated. To ma8e this 6or8 under -orland (..< a template speciali"ation must be provided. class 'y_int { public: 'y_int (int i = 0) { ii = ne$ int(i); } V'y_int () { "elete ii; } private: int ii; }; EE the &ollo$in! te'plate speciali<ation is necessary $hen usin! Iorlan" .JJ inline voi" "estroy ('y_int pointer) { (pointer)K9V'y_int(); } voi" 'ain (voi") { vector('y_int9 v (10); &or (int i = 0; i ( 10; iJJ) { v=i> = ne$ 'y_int(i); } EE allocate" 'y_int 'e'ory an" vector v are "estroye" at en" o& scope } 1hen you use a container of pointers to obBects 6hich do not have an e5plicit destructor defined< a function li8e seP_"elete can be implemented to free all the memory allocated. te'plate (class Dor$ar"@terator9 inline voi" seP_"elete (Dor$ar"@terator &irst, Dor$ar"@terator last) { $hile (&irst 2= last) "elete &irstJJ; } vector(char9 v; char c1 = ne$ char=+0>; strcpy (c1, )5i')); char c+ = ne$ char=+0>; strcpy (c+, ).harles)); v.push_bacL (c1); v.push_bacL (c+); seP_"elete (v.be!in(), v.en"() ); EE vector v is "estroye" at the en" o& scope STL Tutorial page 4% Johannes Weidl The re$aining STL co$ponents The remaining ST, components and topics not dealt 6ith yet 6ill be described here. 5.1 :o, co$ponents ,or; together To ma8e it clear ho6 all ST, components 6or8 together the relations bet6een the components are topic of this section. (ontainers store obBects of arbitrary types. (ontainers are parametri"ed by allocators. Allocators are obBects 6hich encapsulate information about the memory model used. They provide memory primitives to handle memory accesses uniformly. 4very memory model has its characteristic< tailor*made allocator. (ontainers use allocators to do their memory accesses. A change of the memory model used leads to a change of the allocator obBect given as an argument to the container. This means< that on the code level a container obBect is invariant under different memory models. An algorithm is a computation order. So< t6o algorithms should differ in the computations done by them< not in the access method used to read input data and 6rite output data. This can be achieved 6hen data is accessed in a uniform manner. ST, provides a uniform data access mechanism for its algorithms * iterators. Different iterators provide different access modes. The basic input and output unit is the range< 6hich is a 6ell*defined se9uence of elements. &unction obBects are used in combination 6ith algorithms to encapsulate< for e5ample< predicates< functions and operations to e5tend the algorithmsJ utility. Adaptors are interface mappings< they implement ne6 obBects 6ith different or enhanced functionality on the basis of e5isting components. It has to be said that this decomposition of the component space is arbitrary to a certain e5tent but designed to be as orthogonal as possible. This means that interferences bet6een components are reduced as far as possible. The clean< orthogonal and transparent design of the library shall help to simplify application design and redesign decrease the lines of code to be 6ritten increase the understandability and maintainability provide a basis for standard certifying and 9uality assurance as in other areas of system architecture< design and implementation. 5.2 7ector Additionally to the member functions described in section ).%.%< a reserve member function is provided< 6hich informs the vector of a planned change in si"e. This enables the vector to manage the storage allocation accordingly. reserve does not change the si"e of the vector and reallocation happens if and only if the current capacity is less than the argument of reserve. voi" reserve(si<e_type n); After a call of reserve< the capacity @i.e. the allocated storageA of the vector is greater or e9ual to the argument of reserve if reallocation has happened< e9ual to its previous value other6ise. This means< that if you use reserve 6ith a value greater than the actual value of capacity< reallocation happens and after6ards< the capacity of the vector is greater or e9ual to the value given as argument to reserve. To ma8e it clear< 6hy such a member function is provided< remember that reallocation invalidates all the references< pointers and iterators referring to the elements in the se9uence. The use of reserve guarantees that no reallocation ta8es place during the insertions that happen after a call of reserve until the time 6hen the si"e of the vector reaches the capacity caused by the call of reserve. STL Tutorial page 4& Johannes Weidl 1ith this in mind< ta8e a loo8 at e5ercise ).%.%. 1e decided to use a list for storing the single GbitsG< because inserting into a list never invalidates any of the iterators to this container< 6hich 6as essential for the bit*stuff algorithm to 6or8. 2o6< 8no6ing of the e5istence of reserve< 6e can use this member function to reserve a certain vector capacity and are so in a position to use a vector as 6ell. After the call of reserve< 6e can insert elements into the vector till capacity is reached being sure that no reallocation 6ill happen. The argument n of reserve has to be computed by considering a ma5imum number of bits to be bit*stuffed and the 6orst case e5pansion< 6hich happens 6hen bit*stuffing a se9uence only consisting of 1Js. .3 List Unli8e a vector< a list doesnJt provide random access to its elements. So< the member functions be!in< en"< rbe!in and ren" return bidirectional iterators. In addition to the member functions push_bacL and pop_bacL< list provides push_&ront and pop_&ront to add and remove an element at its beginning< because these operations can be done in constant time. The container list provides special mutative operations. It is possible to splice t6o lists into one @member functionH spliceA< that is to insert the content of one list before an iterator position of another. T6o lists can be merged @'er!eA into one using operator( or a compare function obBect< a list can be reversed @reverseA and sorted @sortA. It is also possible to remove all but first element from every consecutive group of e9ual elements @uniPueA. &or an e5act description of all these member functions read D#E< ?.%.#. 5.4 4e<ue As a vector< a de9ue supports random access iterators. -ut in addition to the vector< 6hich only allo6s constant time insert and erase operations at the end< a de9ue supports the constant time e5ecution of these operations at the end as 6ell as at the beginning. Insert and erase in the middle ta8e constant time. -ecause of these constant insert and erase operations at the beginning< a de9ue provides the member functions push_&ront and pop_&ront. 2ote< that insert< push< erase and pop invalidate all the iterators and references to the de9ue. &urther information concerning the de9ue can be found in D#E< ?.%.$. 5.5 Iterator Tags 4very iterator i must have an e5pression iterator_ta!(i) defined< 6hich returns the most spe!i$i! category tag that describes its behaviour. The available iterator tags areH input_iterator_ta!, output_iterator_ta!, &or$ar"_iterator_ta!, bi"irectional_iteerator_ta!, ran"o'_access_iterator_ta!. The most specific iterator tag of a built in pointer 6ould be the random access iterator tag. te'plate (class 59 inline ran"o'_access_iterator_ta! iterator_cate!ory (const 5) { return ran"o'_access_iterator_ta!(); } A user defined iterator 6hich satisfies< for e5ample< the re9uirements of a bidirectional iterator can be included into the bidirectional iterator category. te'plate (class 59 STL Tutorial page 4( Johannes Weidl inline bi"irectional_iterator_ta! iterator_cate!ory (const *y@terator(59&) { return bi"irectional_iterator_ta!(); } Iterator tags are used as Gcompile time tags for algorithm selectionG< D#E< 3.:. They enable the compiler to use the most efficient algorithm at compile time. Imagine the template function binary_search 6hich could be designed to 6or8 6ith bidirectional iterators as 6ell as 6ith random access iterators. To use the tag mechanism< the t6o algorithms should be implemented as follo6sH te'plate(class Ii"irectional@terator, class 59 Ii"irectional@terator binary_search (Ii"irectional@terator &irst, Ii"irectional@terator last, const 5& value, bi"irectional_iterator_ta!) { EE 'ore !eneric, but less e&&icient al!orith' } te'plate(class Nan"o'Access@terator, class 59 Nan"o'Access@terator binary_search (Nan"o'Access@terator &irst, Nan"o'Access@terator last, const 5& value, ran"o'_access_iterator_ta!) { EE 'ore e&&icient, but less !eneric al!orith' } To use binary'search< a 8ind of stub function has to be 6rittenH te'plate(class Ii"irectional@terator, class 59 inline Ii"irectional@terator binary_search (Ii"irectional@terator &irst, Ii"irectional@terator last, const 5& value) { binary_search (&irst, last, value, iterator_cate!ory(&irst)); } At compile time< the compiler 6ill choose the most efficient version of binary_search. The tag mechanism is fully transparent to the user of binary_search. .! *ssociati+e Containers GAssociative containers provide an ability for fast retrieval of data based on 8eys.G< D#E< ?.#. Associative containers< li8e se9uence containers< are used to store data. -ut in addition to that associative containers are designed 6ith an intention to optimi"e the retrieval of data by organi"ing the single data records in a speciali"ed structure @e.g. in a treeA using 8eys for identification. The library provides four different 8inds of associative containersH set< 'ultiset< 'ap and 'ulti'ap. set and 'ap support 'ni0'e "eys< that means that those containers may contain at most one element @data recordA for each 8ey. 'ultiset and 'ulti'ap support e0'al "eys< so more than one element can be stored for each 8ey. The difference bet6een set @'ultisetA and 'ap @'ulti'apA is that a set @'apA stores data 6hich inherently contains the 8ey e5pression. 'ap @'ulti'apA stores the 8ey e5pression and the appropriate data separately< i.e. the 8ey has not to be part of the data stored. Imagine 6e have obBects that encapsulate the information of an employee at a company. An employee class could loo8 li8e thisH STL Tutorial page ) Johannes Weidl class e'ployee_"ata { public: e'ployee_"ata() : na'e ())), sLill(0), salary(0) {} e'ployee_"ata(strin! n, int s, lon! sa) : na'e (n), sLill (s), salary (sa) {} strin! na'e; int sLill; lon! salary; &rien" ostrea'& operator(( (ostrea'& os, const e'ployee_"ata& e); }; ostrea'& operator(( (ostrea'& os, const e'ployee_"ata& e) { os (( )e'ployee: ) (( e.na'e (( ) ) (( e.sLill (( ) ) (( e.salary; return os; } If 6e 6ant to store employee data in a set @'ultisetA< the 8ey has to be included in the obBect storedH class e'ployee { public: e'ployee (int i, e'ployee_"ata e) : i"enti&ication_co"e (i), "escription (e) {} int i"enti&ication_co"e; EE Ley expression to i"enti&y an e'ployee e'ployee_"ata "escription; bool operator( (const e'ployee& e) const { return i"enti&ication_co"e ( e.i"enti&ication_co"e; } }; 2o6 6e are able to declare a set @'ultisetA of employeesH set 11 (e'ployee, less(e'ployee9 9 e'ployee_set; 'ultiset 1+ (e'ployee, less(e'ployee9 9 e'ployee_'ultiset; Using a set @'ultisetA< e'ployee is both the "ey type and the val'e type of the set @'ultisetA. All associative containers are parametri"ed on a class Wey< 6hich is used to define Ley_type< and a so*called !omparison ob*e!t of class .o'pare< for e5ampleH %% To use a set include set.h %# To use a multiset include 'ultiset.h STL Tutorial page 1 Johannes Weidl te'plate (class Wey, class .o'pare = less(Wey9, te'plate (class H9 class Allocator = allocator9 class set { type"e& Wey Ley_type; type"e& Wey value_type; ... }; If 6e 6ant to store employee data in a 'ap @'ulti'apA< the 8ey type is int and the value type is pair(const int, e'ployee_"ata9H 'ap 16 (int, e'ployee_"ata, less(int9 9 e'ployee_'ap; 'ulti'ap 1, (int, e'ployee_"ata, less(int9 9 e'ployee_'ulti'ap; te'plate (class Wey, class 5, class .o'pare = less(Wey9, te'plate (class H9 class Allocator = allocator9 class 'ap { type"e& Wey Ley_type; type"e& pair(const Wey, 59 value_type; ... }; T6o 8eys L1 and L+ are considered to be e9ual if for the comparison obBect co'p< co'p(L1, L+) == &alse && co'p(L+, L1) == &alse< so e9uality is imposed by the comparison obBect and not by operator==. The member function Ley_co'p returns the comparison obBect out of 6hich the associative container has been constructed. value_co'p returns an obBect constructed out of the comparison obBect to compare values of type value_type. All associative containers have the member functions be!in< en"< rbe!in< ren"< e'pty< si<e< 'ax_si<e and s$ap defined. These member functions are e9uivalent to the appropriate se9uence container member functions. An associative container can be constructed by specifying no argument @less(Wey9 is used as default comparison obBectA or by specifying a comparison obBect. It can be constructed out of a se9uence of elements specified by t6o iterators or another associative container. operator= @assignment operatorA is defined for all associative containers. Associative containers provide bidirectional iterators. 2o6 6e 6ant to store some employee data in the set. 1e can use the insert member functionH e'ployee_"ata e"1 ();ohn), 1, 3000); e'ployee_"ata e"+ ()to'), 3, +000); e'ployee_"ata e"6 ()'ary), +, 6000); e'ployee e1 (1010, e"1); e'ployee e+ (+0+0, e"+); e'ployee e6 (6060, e"6); pair(set (e'ployee, less(e'ployee9 9::iterator, bool9 result = e'ployee_set.insert (e1); i& (result.secon") cout (( )insert oL); else cout (( )not inserte"); cout (( en"l (( (result.&irst)."escription.na'e (( en"l; result = e'ployee_set.insert (e1); i& (result.secon") cout (( )insert oL); else cout (( )not inserte"); %$ To use a map include 'ap.h %) To use a multimap include 'ulti'ap.h STL Tutorial page 2 Johannes Weidl pair('ap (int, e'ployee_"ata, less(int9 9::iterator, bool9 result1 = e'ployee_'ap.insert ('aLe_pair (1010, e"1)); 'ultiset (e'ployee, less(e'ployee9 9::iterator result+ = e'ployee_'ultiset.insert (e1); 'ulti'ap (int, e'ployee_"ata, less(int9 9::iterator result6 = e'ployee_'ulti'ap.insert ('aLe_pair (1010, e"1));
0utputH insert o" *ohn not inserted 0ote? &or users of -orland (.. it has to be said that the above map and multimap insert operations can only be compiled 6ith a change in the code in 'ap.h and 'ulti'ap.h. Instead of Gtype"e& pair(const Wey, 59 value_typeG I used Gtype"e& pair(Wey, 59 value_typeG. insert ta8es an obBect of type value_type and returns a pair consisting of an iterator and a bool value. The bool value indicates 6hether the insertion too8 place. In case of an associative container supporting uni9ue 8eys< the iterator points to the element 6ith the 8ey e9ual to the 8ey of the element specified as argument< in case of an associative container supporting e9ual 8eys to the ne6ly inserted element. insert does not affect the validity of iterators and references to the container. A second version of insert ta8es a range specified by t6o iterators and inserts the appropriate elements into the associative container @the return value is voi"AH pair(int, e'ployee_"ata9 a=+> = { 'aLe_pair (+0+0, e"+), 'aLe_pair (6060, e"6) }; e'ployee_'ap.insert (&a=0>, &a=+>); The &in" member function ta8es a 8ey value and returns an iterator< 6hich indicates the success of the search operationH 'ap (int, e'ployee_"ata, less(int9 9::const_iterator i = e'ployee_'ap.&in" (6060); i& (i == e'ployee_'ap.en"() ) cout (( )not &oun"); else cout (( (i).secon".na'e; 0utputH mary 'ap is the only associative container 6ith provides the subscribe operator @oprator=>A to address elements directlyH e'ployee_"ata " = e'ployee_'ap=+0+0>; cout (( "; 0utputH tom , 1999 The erase member function can ta8e a value of type Ley_type< a single iterator or a range specifying the element or elements to be erasedH e'ployee_'ap.erase (6060); e'ployee_'ap.erase (e'ployee_'ap.be!in() ); e'ployee_'ap.erase (e'ployee_'ap.be!in(), e'ployee_'ap.en"() ); i& (e'ployee_'ap.e'pty() ) cout (( )e'ployee_'ap is e'pty); 0utputH employee3map is empty STL Tutorial page 3 Johannes Weidl erase invalidates only the iterators and references to the erased elements. Since it doesnJt ma8e sense to store more than one employee under an employee 8ey< for the demonstration of an associative container supporting e9ual 8eys a slightly different e5ample is used. A number of employees is stored under the same 8ey 6hich represents a department code. 1e can use the e'ployee_'ulti'ap container declared earlier in this sectionH EE e'ployee_'ulti'ap is e'pty e'ployee_'ulti'ap.insert ('aLe_pair(101, e"1)); EE "epart'ent co"e 101 e'ployee_'ulti'ap.insert ('aLe_pair(101, e"+)); e'ployee_'ulti'ap.insert ('aLe_pair(10+, e"6)); EE "epart'ent co"e 10+ count ta8es a 8ey value and returns the number of elements stored under this 8ey value. 'ulti'ap (int, e'ployee_"ata, less(int9 9::si<e_type count = e'ployee_'ulti'ap.count (101); cout (( count; 0utputH 1 lo$er_boun" (L) 6ith L of type Ley_type returns an iterator pointing to the first element 6ith 8ey not less than L. upper_boun" (L) returns an iterator pointing to the first element 6ith 8ey greater than L. ePual_ran!e (L) returns a pair of iterators 6ith the first iterator being the return value of lo$er_boun" (L) and the second being the return value of upper_boun" (L). ostrea'& operator(( (ostrea'& os, const pair(int, e'ployee_"ata9& p) { os (( )e'ployee: ) (( p.secon".na'e (( ) ) (( p.secon".sLill (( ) ) (( p.secon".salary; return os; } type"e& 'ulti'ap (int, e'ployee_"ata, less(int9 9::iterator ;; pair(;, ;9 result = e'ployee_'ulti'ap.ePual_ran!e (101); copy (result.&irst, result.secon", ostrea'_iterator(pair(int, e'ployee_"ata9 9 (cout , )Mn)) ); 0utputH *ohn . ,999 tom , 1999 STL Tutorial page 4 Johannes Weidl ! Cop-right The spell*chec8er e5ample from section ).$ is a (opyright %>>3 of . !a"ayeri and G.Trausmuth * TU 1ien. All code pieces 6ith a shaded frame are subBect to the follo6ing copyright notice by 7e6lett Pac8ardH E
.opyri!ht (c) 144, 0e$lettKTacLar" .o'pany
Ter'ission to use, copy, 'o"i&y, "istribute an" sell this so&t$are an" its "ocu'entation &or any purpose is hereby !rante" $ithout &ee, provi"e" that the above copyri!ht notice appear in all copies an" that both that copyri!ht notice an" this per'ission notice appear in supportin! "ocu'entation. 0e$lettKTacLar" .o'pany 'aLes no representations about the suitability o& this so&t$are &or any purpose. @t is provi"e" )as is) $ithout express or i'plie" $arranty.
E This tutorial is permitted to be used for academic and teaching purposes in 6hole or in part if the follo6ing copyright notice is preservedH (opyright %>>3< %>>: !ohannes 1eidl * TU 1ien All other use< especially if commercial< can only be granted by the author himself * feel free to contact me. % Literature D%E Stroustrup< -BarneH The (.. programming language ** #nd ed. !une< %>>$ D#E ,ee< engT Stepanov< Ale5H The Standard Template ,ibrary 7P ,abaratories< %3/% Page ill +oad< Palo Alto< (A >)$/) &ebruary ;< %>>3 D$E ST,.. The 4nhanced Standard Template ,ibrary< Tutorial I +eference anual odena Soft6are Inc.< #$: 2. Santa (ru" Ave< Suite #%$< ,os Gatos (A >3/$/ %>>) D)E Standard Template ,ibrary +eference +ensselaer Polytechnic Institute< %>>) includes as chapter : The ST, 0nline Algorithm +eference (oo8< +obert !r.T usser< David +.T Pale6s8i< Lenneth !. online at httpHCC666.cs.rpi.eduCmusserCstl.html STL Tutorial page Johannes Weidl