A Practical Guide to STL: Jeff Bogan
original:
http://www.codeproject.com/vcpp/stl/practicalguitestl.asp
translation:
Winter
STL Practice Guide
1 Introduction 2 Background 3 Using Code 4 Defining 5 Hello Word Programs 6 STL's troubles: 7 Namespace 20 Translator Note
Winter Note: This is a very good article, Zhou Xiang has been translated. Just feel that there are some things that are not properly, especially some terms, so he re-translates.
1 Introduction For all C programmers today, STL (standard template library abbreviations) is very nice technology. But I have to remind it that it is necessary to use a certain difficulty in use, for example, there is a steep learning curve, which uses many names to know, it can know what it means (perhaps because all the names of all good books are used Empty). But once you learn STL, you will benefit from it. STL is more flexible and powerful than the MFC container.
The advantages are as follows:
It can be easily sorted and searched. More secure and easier to debug. You can read the code Note 1 of UNIX programmers. Will add skills to your resume.
2 Background The purpose of writing this document is to let readers can have a good start in this challenging computer science field, do not have to fully understand the endless japanese terms and dull rules, those jaices and rules are only stalers used for self Creative products for entertainment.
3 Using the code This document has a strong guiding role on the reader on the way of using STL practices.
4 definition
Template - macro of class (and structure, data type, and function). Sometimes it is also called cookie cutter. Simultaneously, as a generic form - a class template called a model class, the same, a function template called a modal function. STL - Standard Template Library, written by a group of smart people, is now used as part of the standard C language. Container - a class that can accommodate certain data. There are VECTOR, SET, MAP, MULTIMAP, and DEQUE, etc. in STL. Vector - a base data template is a container. Iterator - a very interesting word, actually a pointer to the internal elements of the STL container. It completes many other features at the same time.
5 Hello Word Program i Always Wanted to Write One and Here IS My Golden 24 Karet Opportunity: A Hello World Program This program converts a string into a character vector, then display the entire string on a character character. VECTOR is like a garden that is growing, in all containers in STL, about half is a vector, so you can say that if you master this program, then you understand half of the entire STL.
// Program: Vector Demo 1
// purpose: used to demonstrate STL VECTOR
// #include "stdafx.h" - If you need this file if you need to include this file [[# explainin2] [Note 2]]
#include
#include
Using namespace std; // Make sure the namespace is STD
Char * szhw = "Hello World";
/ / It is well known that this is an array of characters ending with NULL.
Int main (int Argc, char * argv [])
{
Vector
Vector
// Initialize the character vector, loop the entire string, put each character into the vector until the NULL character at the end of the string
Char * cptr = szhw; // Hello World string first address
While (* CPTR! = '/ 0')
{vec.push_back (* cptr); CPTR ;}
/ / Push_back function Plug the data into the vectors
/ / Print each character in the existing STL array to the screen
FOR (vi = vec.begin (); vi! = vec.end (); vi )
// This is the standard judgment method in STL - often uses "! =" Rather than "<"
// Some containers may not have a heavy load operator "<".
// begin () and end () will get an iterator (pointer) at the beginning of the vector and the end of the end of the end.
{COUT << * vi;} // Use indirect operattles (*) from the iterator
Cout << Endl; // Output, print "/ n"
Return 0;
}
Push_back is a standard function that is used to insert data into the vector or DEQUE container. INSERT is a function of similar functions, suitable for all containers, but usage more complicated. End () actually represents the last position to add one so that the loop can be performed normally - it returns the pointer to the most close-to-array boundary. Just like an array in a normal cycle, such as for (i = 0; i <6; i ) {ar [i] = i;} --ar [6] does not exist, this element does not reach this element in the loop. Therefore, there will be no problem in the cycle.
One of the troubles of STL:
STL is annoying place to initialize it. The initialization of the containers in the STL is more troublesome than that of the C / C array. You can only be an element, or first initialize a normal array and then fill in the container by transformation. I think people can usually do this:
// Program: Initialization Demo
// purpose: to Demonstrate Initialization of Stl Vectors
#include
#include
Using namespace std;
INT Ar [10] = {12, 45, 234, 64, 12, 35, 63, 23, 12, 55};
Char * str = "Hello World";
Int main (int Argc, char * argv [])
{
Vector
Vector
Return 0;
}
In programming, there are many ways to complete the same job. Another method of filling the vector is to use more familiar square brackets, for example:
// Program: Vector Demo 2
// Purpose: To Demonstrate STL VECTORS WITH
// counters and Square Brackets
#include
#include
Using namespace std;
Char * szhw = "Hello World";
Int main (int Argc, char * argv [])
{
Vector
// the argument initializes the memory footprint
INT I, K = 0;
Char * cptr = szhw;
While (* CPTR! = '/ 0')
{VEC [K] = * CPTR; CPTR ; K ;}
For (i = 0; i {cout << vec [i]; Cout << Endl; Return 0; } This example is clearer, but does not use an iterator operation, and define additional integers as a subscript, and you must clearly describe how much memory space allocation as VECTOR is in the program. 7 Namespace (Namespace) The concept related to STL is namespace. STL is defined in the STD namespace. There are three ways to declare the namespace used: Use this namespace to use this namespace, on top of the file, but join: USING NAMESPACE STD; In simplest works, this is the simplest and best way. Position your code directly to the STD namespace, This is the Simplest and Best for Simple Projects, Limits You To The Std Namespace, Anything You Add Is Improperly Put in The Std Namespace (I Think You Go To Heck For Doing This). Specify Each and Every Template Before Use (Like Prototyping) Using std :: end1; using std :: flush; using st :: set; using st :: insert; This is Slightly More Tedious, Although A Good Mnemonic for the Functions That Will BE Used, and you can interlace other namespaces easily. Every Time You Use A Template from the std namespace, Use the std scope specifier. Typedef st :: vector ........................ .. In addition, you can put using namespace std within any scope, for example, at the top of a function or within a control loop Some TipsTo avoid an annoying error code in debug mode, use the following compiler pragma.: #pragma Warning (Disable: 4786) Another Gotcha is: You Must Make Sure That The Spaces Are Placed Between Your Angle Brackets and the name. This is because >> Is The Bit Shift Operator, SO: Vector > VECLIS; Will Give An Error. Instead, Write IT: Vector > VECLIS; To Avoid Compiration Errors. Another Container - The Set This is the explanation lifted from the MS help file of the set: "The template class describes an object that controls a varying-length sequence of elements of type const Key Each element serves as both a sort key and a value The sequence is.. represented in a way that permits lookup, insertion, and removal of an arbitrary element with a number of operations proportional to the logarithm of the number of elements in the sequence (logarithmic time). moreover, inserting an element invalidates no iterators, and removing an Element Invalidates Only Those Iterators That Point At The Removed Element. " An alternate, more practical, definition is: A set is a container that contains all unique values This is useful for cases in which you are required to collect the occurrence of value It is sorted in an order that is specified at the instantiation of.. the set. If you need to store data with a key / value pair, then a map is a better choice. A set is organized as a linked list, is faster than a vector on insertion and removal, but slightly slower on search and addition TO END. AN EXAMPLE PROGRALD BE: // Program: set demo // purpose: To Demonstrate STL Sets # include # include #include Using namespace std; INT Main (int Argc, char * argv []) {set StRSET; SET :: Itet.insert ("Cantaloupes"); strset.insert ("apple"); strset.insert ("Orange"); strset.insert ("banana"); strset.insert ("grapes"); STRSET.INSERT ("grapes"); // this one overwrites the prep (si! = strset.begin (); si! = strset.end (); si ) {cout << * si << " Cout << Endl; Return 0; // Output: Apple Banana Cantaloupes Grapes Orange IF you want to become an stl fanatic, you can also replace the output loop in the program with the following line. Copy (strSet.begin (), strset.end (), Ostream_Iuterator (cout, "")); While Instructive, I Find this Personally Less Clear and Prone to Error. If you see it it, count you know what it does. All The STL Containers ...................... .. * Vector -. Your standard safe array It is expanded in the "front" direction only * deque -. Functionally the same as a vector Internally, it is different It can be expanded in both the front and back * list -... Can . only be traversed one step at time If you are already familiar with the concept of a list, an STL list is doubly linked (contains pointer to both the previous and next value) * set -.. contains unique values that are sorted * map - Sorted Set of Paired Values, One of Which Is The Key On Which Sorts and Searches Occur, And The Value Which Is Retrieved from The Container. Eg INSTEAD OF AR [43] = "Overripe", a map lets you do this ar [ "banana"] = "overripe". SO if you wanted to Draw Up A bit of information keyed on full name is easily done. * MultiSet - Same as a set, but do necessarily has unique values. * MultiMap - Same as a Map, But Does Not Necessarily Have Unique Keys.note: if You Are Reading The MFC Help Then You Will Also Come Across The EffICIENCY Statement O f each container. IE (log n * n) insertion time. Unless you are dealing with very large number of values, you should ignore this. If you start to get a noticeable lag or are dealing with time critical stuff then you should learn more About The Proper Efficiency of Various Containers. How to use a map with some class The Map Is A Template That Uses a Key To Obtain A Value. Another issue is that you will want to use your own classes instead of data types, like int that has been used up to now. To create a class that is "template-ready", you must be ensure that the class contains certain member functions And Operators. The Basics Are: * Default constructor (empty, usually) * copy constructor * overload "=" You would overload more operators as required in a specific template, for example, if you plan to have a class that is a key in a map you would have to overload RELATIONAL OPERATORS. But this is another story. // Program: Map Own Class // Purpose: To Demonstrate A Map of Classes #include #include #include #include usingspace std; class CStudent {public: int nStudentID; int nAge; public: // Default Constructor - Empty CStudent () {} // Full constructor CStudent (int nSID, int nA) {nStudentID = nSID; nAge = nA;} // Copy constructor CStudent (const CStudent & ob) {nStudentID = ob.nStudentID; nAge = ob.nAge;} // Overload = void operator = (const CStudent & ob) {nStudentID = ob.nStudentID; nAge = ob.nAge;}}; INT Main (int Argc, char * argv []) {map Mapstudent ["Joe Lennon"] = CStudent (103547, 22); MapStudent ["Phil McCartney?"] = CStudent (100723, 22); MapStudent ["Raoul Starr"] = CStudent (107350, 24); mapstudent ["gordon Hamilton "] = CStudent (102330, 22); // Access via the name cout << "The Student Number for Joe Lennon IS" << (MapStudent [Joe Lennon "]. NstudentId << ENDL; Return 0;} Typedef If you like to use typedef, this an example: Typedef set Set_int; typedef set_int :: item set_int_iter One convention is to make the upper case with understandcores. ANSI / ISO STRING ANSI / ISO strings are commonly used within STL containers. It is your standard string class, widely praised except for its deficiency of no format statement. You must instead use << and the iostream codes (dec, width, etc.) to string together Your string.use c_str () To Retrieve a Character Pointer, When Necessary. Iterators I said that iterators are pointers, but there is more They look like pointers, act like pointers, but they are actually embedded in which the indirection operator (unary *) and -..> Have been overloaded to return a value from the container It is a bad idea to store them for any length of time, as they usually invalid after a value has been added or removed from a container. They are something like handles in this regard. The plain iterator can be altered, so that the container is To be traverseed in Different Ways: * Iterator - for Any Container Other Than The Vector, You Can, That Is You CAN Only Use The Operator, NOT The - OR = Operator on It. for Vector Only You CAN Use any of =, - a non-vector container, replace iterator with reverse_iterator, begin () with rbegin (), and end () with rend (), will then traverse backwards * const_iterator -.. a forward iterator that returns a const value Use this if You want to make it clear what this point. * const_reverse_iterator - a Reverse Iterator That Returns a const value. Sorting Order in Sets and Maps . Templates have other parameters besides the type of value You can also pass callback functions (known as predicates - this is a function of one argument that returns a bool value) For example, say you want a set of strings that are automatically sorting in. Ascending Order. You Would SIMPLY CREATE A SET CLASS IN THIS WAY: SET > set1 Greater IS Another Template for A Function (GeneriC Function) Which is buy to sort value Set > set1 There Are Many Other Cased You Must Pass A Predicate As Parameter To The Stl Class, In Algorithms, Described Below. STL Annoyance # 2 - Long Error Messages The templated names get expanded for the compiler, so when the compiler chokes on something, it spits out extremely long error messages that are difficult to read. I have found no good way around this. The best is to develop the ability to find and focus on the end of the error code where the explanation is located Another related annoyance:.. if you double click on the template error, it will take you to the point in the code within the template code, which is also difficult to read Sometimes, IT Is Best Just To Carefully Re-Examine Your Code, And Ignore The Error Messages Completely. Algorithms Algorithms are functions that apply to templates. This is where the real power of STL starts to show up. You can learn a few function names that usually apply to most of the template containers. You can sort, search, manipulate, and swap with the Greatest's Contain A Range With Hich The Algorithm Performs. EG: Sort (vec.begin () 1, vec.end () - 1) Sorts Everything But The First and Last Values.The Container Itself Is Not Passed to the algorithm, just two iterators from the container that bookend a range. In this way, algorithms are not restricted by containers directly, but by the iterators supported by that specific algorithm. In addition, many times you will also pass a name of a Specially Prepared Function (Those Afore Mentioned Predicates) AS An Argument. You Can Even Pass Plain Old Values. EXAMPLE OF Algorithms in Play: // Program: Test Score // Purpose: To Demonstrate The Use of Algorithm // with respect to a vector of test scores #include // if you want to use an // algorithm this is the header used. #Include // (for accumulate) #include #include Using namespace std; INT testscore [] = {67, 56, 24, 78, 99, 87, 56}; // Predicate That Evaluates a passed test bool passed_test (int N) {return (n> = 60); // Predicate That Evaluates a failed test bool failed_test (int N) {return (n <60);} INT Main (int Argc, char * argv []) {int total; // initialize a vector with the data in the testscore arch vector VECTESTSCORE (Testscore, Testscore Sizeof (Testscore) / sizeof (int)); Vector :: Iterator vi; // sort and display the vector sort (vectestscore.begin (), vectestscore.end ()); cout << "sorted test score: << Endl; for (vi = vectestscore.begin (); vi = vectestscore.end (); vi ) {cout << * vi << ",";} cout << endl; // display statistics // min_element returns an iterator to the // element that is the minimum value in the range // Therefor * operator must be used to extract the value vi = min_element (vecTestScore.begin (), vecTestScore.end ()); cout < <"The Lowest Score Was" << * vi << "." << endl; // Same with max_element vi = max_element (vectestscore.begin (), vectestscore.end ()); cout << "The highest score was" << * vi << "." << endl; // use a predicate function to determine the number who passed cout << count_if (vectestscore.begin (), vectestscore.egin (), vectestscore.end (), passed_test) << "out of" << vectestscore.Size () << "students passed the Test "<< Endl; // and who failed cout << count_if (vectestscore.begin (), vectestscore.egin (), filed_test) << "out of" << vectestscore.size () << "Students Failed The Test" << ENDL; // Sum the score = Accumulate (vectestscore.begin (), vectestscore.egin (), 0); // THEN DISPLAY THE AVERAGE COUT << "Average Score WAS" << (Total / (INT) (vectestscore.size ())) << ENDL; Return 0;} See you latd, Allocator These are used in the initialization stages of a template. They are mysterious behind the scenes type of creatures, and really only of concern if you are doing high level memory optimization, and are best considered to be black boxes. Usually, you never even specify them as they are default parameters that are generally not tinkered with. It is best to know what they are though in case they show up on one of those employment tests. Derive or Embed TemplatesAny way that you use a regular class, you can use an STL Class. IT can be equbedded: Class CParam {string name; string unit; vector Vecdata; Or use as a base class: Class CParam: Public Vector {String name; DeriVation SHOULD BE Used with Some Caution. It is up to you as to the form.. Templates forin Templates To create a more complex Data Structure, you can Nest A Template Withnin A Template. It is best to type to use the inner template again. // Program: Vector of product demo // purpose: To Demonstrate Nested STL Containers #include #include Using namespace std; TypedEf Vector VEC_INT; INT INP [2] [2] = {{1, 1}, {2, 0}}; // regular 2x2 array to place {Template int main (int Argc, char * argv [) {INT i, J Vector; Vecvec; // if you want to do this in all one step it looks like this // vector > VECVEC; // Fill it in with the array vec_int v0 (INP [0], INP [0] 2); // passing tour point to be copied to the vector vec_int v1 (INP [1], INP [1] 2); VECVEC.PUSH_BACK (V0); VECVEC.PUSH_BACK (V1); For (i = 0; i <2; i ) {for (j = 0; j <2; j ) {cout << VECVEC [i] [j] << ";} cout << Endl;} Return 0 } // Output: // 1 1 // 2 0 Although cumbersome to initialize, once completed and filled in, you have a 2 dimensional array that is indefinitely expandable (until memory space runs out). The same can be done for any combination of containers, as the situation requires. Conclusion STL IS Useful, But Not Without It: if You Learn It: if You Learn It, You Will Be Like A Tiger with The Claws of A Lion. 20 translator's note [Note 1] STL is a cross-platform, here is a reader using the Windows platform. [Note 2] When using VC, if you choose to precompile, each CPP file must contain a header file: "stdafx.h"