910 likes | 1.26k Views
Unit - 11. Standard Template Library. C++ Library of templates. Unit Introduction. This unit covers standard template library. Unit Objectives. After covering this unit you will understand… Standard template library String library IOStream library General template library
E N D
Unit - 11 Standard Template Library C++ Library of templates
Unit Introduction This unit covers standard template library
Unit Objectives After covering this unit you will understand… • Standard template library • String library • IOStream library • General template library • STL containers and iterators • STL algorithms
Introduction • STL stands for ‘Standard Template Library’ • Complements the C++ libraries • STL provides certain features, which include: • String library • Input/Output stream library • Localization library • Containers library
Introduction (contd.) • Iterators library • Algorithms library • Numerics library • Diagnostics library • Language Support library • General Utilities library • The purpose of STL is to provide standardised set of tools • These tools become the building blocks of most programs
Strings Library • It provides a set of functions to implement the low-level manipulation features • A string is a character array with a null terminator (binary zero) • STL uses string object for string manipulation
Characteristics of String Object • A string object has: • Starting location in memory • contents • Length • no NULL terminator • A string automatically resizes according to length of its contents • In case of reference counting, string may occupy specific physical memory
Advantages of String Object • It has the following three advantages over the character array, used in C++: • Checks overwriting array bounds • Checks for uninitialized pointers before using strings • Releases memory storage for dangling pointers
Creating Strings • Create an empty string and defer initializing it with character data • Initialize a string by passing a literal, quoted character array as an argument to the constructor • Initialize a string using ‘=‘ • Use one string to initialize another • Use a portion of either a C char array or a C++ string
Creating Strings (contd.) • Combine different sources of initialization data using operator+ • Use the string object’s substr( ) member function to create a substring
Example: Creating Strings #include <string.h> #include <iostream.h> void main() { string s1 (”This is String 1"); string s2 = “This is String 2”; // Copy the first 8 chars string s3(s1, 0, 8); // Copy 3 chars from the 5th character of the source string s4(s2, 5, 3); // Copy all sorts of stuff string mixedStuff = s4 + “hmmm” + s1.substr(10, 5); // substr() copies 5 chars at element 10 cout << mixedStuff << endl; }
Operating on Strings • You can perform four basic operations on a string: • Append • Insert • Concatenate • Replace
Example: Operating on Strings #include <string.h> #include <iostream.h> void main() { string s1(”This is String 1."); // How much data have we actually got? cout << "Size = " << s1.size() << endl; // How much can we store without reallocating cout << "Capacity = ” << s1.capacity() << endl; s1.insert(1, "This is Inserted at index 1."); // Make sure that there will be this much space s1.reserve(50); // Add this to the end of the string s1.append("I've been working too hard."); string tag(“String”); // tag to find int start = s1.find (tag); // get the start index s1.replace (start, tag.size(), “hey there”); }
Searching in String • Following are useful functions used for string searching: • find(); • find_first_of(); • find_last_of(); • find_first_not_of(); • find_last_not_of(); • rfind();
Example: Searching in Strings #include <string> #include <iostream> void main() { string s1(”This is String 1."); // find the tag string tag(“String”); // get the start index int start = s1.find (tag); // replace the tag totally with the new string s1.replace (start, tag.size(), “hey there”); // finds the ‘i’ in String in s1 int current = s1.rfind(“i”); // finds the first space after ‘This’ in s1 int space = s1.find_first_not_of(“ “); }
String Comparison • Compares the ASCII values of the string characters • Returns 0 if both strings match • Returns 1 if string1 has greater ASCII value • Returns -1 if string2 has greater ASCII value • Two types of syntax: • string1.compare(string2); • strcmp(string1, string2);
Example: String Comparison #include <iostream.h> #include <string.h> void main() { string s1(“This is One String”); string s2(“This is the Other String”); int result = strcmp(s1, s2); int caseInsensitive = strcmpi(s1, s2); int result2 = s1.compare(s2); switch (result) { case 0: cout<<“Both the Strings are equal”; break;
Example: String Comparison (contd.) case -1: cout<<“String1 is lexically less than String2”; break; case 1: cout<<“String1 is lexically greater than String2”; break; } // end switch statement } // end main
IOStream Library • Deals with the following I/O functions in a safe, efficient and easier manner: • Standard Input • Standard Output • Files • Memory Blocks
General Template Library • Templates provide an interface to assign variable type or class type, to be used at runtime • There are two types of Template arguments: • Non-type template arguments • Default template arguments
Example: Non-type Template Arguments #include <string.h> #include <sstream.h> template<typename T> std::string toString(const T& templateVar) { std::ostringstream output; output << templateVar; return output.str(); } void main() { int i = 1234; cout << "i == \"" << toString(i) << "\"\n"; float x = 567.89; cout << "x == \"" << toString(x) << "\"\n"; }
Example: Default Template Arguments // Using 'typename' to say it's a type, // and not something other than a type template<class T> class TemplateClass { // without typename, it is an error typename T AnyVarType; public: void TemplateFunc() { AnyVarType.Function(); } }; class NormalClass { public: void Function() {} };
Example: Default Template Arguments (contd.) void main() { NormalClass normalObj; TemplateClass<NormalClass> templateObj; templateObj.TemplateFunc(); }
Typedef a typename • It is recommended to use typedef when using typename /* The following causes a variable to be declared of type Seq::iterator */ // instead of using typename only typename Seq::iterator ItType; // use typedef typedef typename Seq::iterator SeqIteratorType; // now SeqIteratorType is a type and can be used as SeqIteratorType it;
Example: Using typename Instead of Class // Using 'typename' in the template argument list template<typename T> class TemplateClass { }; int main() { TemplateClass<int> templateObj; }
Function Templates • You can create Function Templates in places, where • you have a number of functions, • that look identical, • but have different data types
STL Containers and Iterators • Container classesare the solution to a specific kind of code reuse problem • They are building blocks used to create object-oriented programs • They make the internals of a program much easier to construct • They are sometimes referred to as Collection Classes • A container class describes an object that holds other objects
Why Use Containers? • Containers solve the problem of creating objects at runtime • You create another type of object, the new type of object holds other objects, or pointers to objects • It will expand itself whenever necessary to accommodate everything you place inside it
Why Use Containers? (contd.) • You don’t need to know how many objects you’re going to hold in a collection • You just create a collection object and let it take care of the details • You can add/delete elements in a container • For fetching/comparing/manipulating objects within a container, you need an iterator
Iterators • Iterator’s job is to iterate the elements within a container • Present them to the user of the iterator • The container, via the iterator, is abstracted to be simply a sequence • The iterator allows you to traverse that sequence without worrying about the underlying structure – that is, whether it’s a vector, a linked list, a stack or something else
Iterators (contd.) • Gives the flexibility to easily change the underlying data structure without disturbing the code
Example: String Containers #include <string.h> #include <vector.h> #include <fstream.h> #include <iostream.h> #include <iterator.h> #include <sstream.h> void main(int argc, char* argv[]) { ifstream in(argv[1]); vector<string> stringVector; string inputLine; // Add to strings container while(getline(in, inputLine)) stringVector.push_back(inputLine); int i = 1; vector<string>::iterator vectorIterator; // iterator
Example: String Containers (contd.) for(vectorIterator = stringVector.begin(); vectorIterator != stringVector.end(); vectorIterator++) { ostringstream out; // define output string stream // object out << i++; // outputs the element number *vectorIterator = out.str() + ": " + *vectorIterator; } // write strings to console // create ostream iterator to write to console ostream_iterator<string> os_it(cout, "\n"); //copy contents of ‘strings’ to console using the iterator copy(stringVector.begin(), stringVector.end(), os_it); // string objects clean themselves up when they go out of // scope }
Types of Containers • There are two types of containers • Sequence Containers: These containers keep the sequence of objects in whichever order you want to establish • Associative Containers: These containers keep {key, value} pairs, and store/retrieve data using associations
Sequence Containers • These containers keep the sequence of objects in whichever order you want to establish • The different sequence containers are: • Vector • Deque • List • Set • Stack • Queue
Vectors • It has array-style indexing but also can expand dynamically • It maintains its storage as a single contiguous array of objects • It keeps everything in a single sequential block of memory
Example: Vectors #include <iostream.h> #include <vector.h> #include <algorithm.h> int Noisy() { // return some random integer } void main() { vector<int> v; v.reserve(11); // make room for 11 integers ostream_iterator<int> out(cout, " "); copy(v.begin(), v.end(), out); // write to console vector<int>::iterator it = v.begin() + v.size() / 2; v.insert(it, Noisy()); // insert an element in middle copy(v.begin(), v.end(), out); // write to console v.erase(it); // erasing an element from vector copy(v.begin(), v.end(), out); // write to console }
Deque • The deque (double-ended-queue, pronounced “deck”) is optimized for adding and removing elements from either end • Deque uses multiple blocks of sequential storage (keeping track of all the blocks and their order in a mapping structure)
Example: Deque #include <deque.h> #include <iostream.h> #include <iterator.h> void main() { deque<int> dequeObj(100, 0); ostream_iterator<int> out(cout, " ") // No problem iterating from beginning to end, // even though it spans multiple blocks copy(dequeObj.begin(), dequeObj.end(), out); deque<int>::iterator dequeIterator = dequeObj.begin() + dequeObj.size() / 2; // Walk the iterator forward as you perform // a lot of insertions in the middle for(int j = 0; j < 1000; j++) { cout << j << endl;
Example: Deque (contd.) dequeObj.insert(dequeIterator++, j); // Eventually // breaks } //end for loop } // end main()
List • It is implemented as a doubly-linked list • It is designed for rapid insertion and removal of elements in the middle of the sequence • A list is so slow when randomly accessing elements that it does not have an operator[] • It has a memory overhead of each link, which requires a forward and backward pointer
Example: List #include <list.h> #include <iostream.h> void main() { // create list 100 elements initialized with 0 list<int> li(100, 0); // create iterator to traverse the list list<int>::iterator iter = li.begin(); // insert new elements with value 1 for(int k = 0; k < 50; k++) li.insert(iter++, 1); // No problem cout << *iter; // prints first 0 li.erase(iter); // erases first 0 --iter; cout << *iter; // prints the 1 *iter = 2; // replaces 1 with 2 at the current position }
Set • It produces a container that will accept only one of each thing you place in it • It also sorts the elements in a balanced binary tree to provide rapid lookups • It produces sorted results when you traverse it
Example: Set #include <string.h> #include <set.h> #include <iostream.h> #include <fstream.h> const char* delimiters = "\t;()\"<>:{}[]+-=&*#.,/\\~"; void main(int argc, char* argv[]) { ifstream in(argv[1]); set<string> wordListSet; string line; while(getline(in, line)) { // Capture individual words: char* token = strtok((char*)line.c_str(), delimiters);
Example: Set (contd.) while(token) { // Automatic type conversion: wordListSet.insert(token); token = strtok(0, delimiters); } } // end outer while loop ostream_iterator<string> out(cout, "\n") // Output results: copy(wordListSet.begin(), wordListSet.end(), out); } // end main()
Stack • The stack is classified as adapters, which means they are implemented using one of the basic sequence containers: vector, list or deque • The stack has one pointer, which points to the top of the stack • You can add (push) or delete (pop) elements from the top of the stack only
Example: Stack #include <iostream.h> #include <fstream.h> #include <stack.h> #include <list.h> #include <vector.h> #include <string.h> typedef stack<string> Stack1Type; // Default: deque<string> typedef stack<string, vector<string> > Stack2Type; // Vector typedef stack<string, list<string> > Stack3Type; // List void main(int argc, char* argv[]) { ifstream in(argv[1]); Stack1Type textLines; // Try the different versions // Read file and store lines in the stack: string line;
Example: Stack (contd.) while(getline(in, line)) textLines.push(line + "\n"); // Print lines from the stack and pop them: while(!textLines.empty()) { cout << textLines.top(); textLines.pop(); } } // end main()
Queue • The queue is a restricted form of a deque • You can only enter elements at one end, and pull them off the other end • The queue is an adapter class like stack, in that it is built on top of another sequence container
Priority Queues • It’s a special type of queue • When you push( ) an object onto a priority_queue, that object is sorted into the queue according to a function or function object • The priority_queue ensures that when you look at the top( ) element it will be the one with the highest priority