Published on

Published in: Technology, Education
  • Be the first to comment

  • Be the first to like this

No Downloads
Total views
On SlideShare
From Embeds
Number of Embeds
Embeds 0
No embeds

No notes for slide


  1. 1. Overview Overview tandard Template Library (STL) is understand both the interface and S a powerful template library for implementation of your symbol table: only C++, which is used extensively in you know your program well, as it is non- the industry. It provides generic, standard. fundamental data structures and Instead, when you use STL for algorithms useful for most of the programs. So, implementing your symbol table, you can make it avoids reinventing the wheel and provides use of a map (or a multi-map) container; use code that is well tested, versatile, efficient and various generic algorithms (binary_search, sort generic. For example, if you want to write a etc) to operate on it; and make use of iterators symbol table for your toy compiler, you can go to traverse the table as required. To be specific: ahead and write your own symbol table. You need not write a full-fledged However, this approach suffers from several implementation of the symbol table: you can disadvantages: concentrate on solving the actual, specific The effort required to write a full-fledged, problem of providing a symbol table. effective and efficient symbol table is You can reasonably expect the STL library substantial. you have to be rigorously tested. The hand-written code needs to undergo Though STL is a generic library, it is rigorous testing (since the symbol table is a designed with efficiency in mind. It is in fact very important piece of a compiler). Finding a very efficient library. and fixing problems can take significant STL is an industry standard and widely used amounts of time and energy. library—so you can have any competent C++ The data structure needs to be efficient and programmer get some exposure to the STL effective: achieving this is not easy. library. A programmer who may possibly If some other programmers are assigned to maintain or extend your symbol table will maintain or extend your symbol table in the find it easy to understand the future, they will find it very difficult to implementation of your symbol table. A Ready Reckoner for the Standard Template Library Learn about the many benefits of the Standard Template Library in this introductory article. 78 MAY 2007 | LINUX FOR YOU |
  2. 2. Overview The list is not exhaustive, yet it covers a few very checked. On the other hand, the at method does range important reasons to (re)use standard components as checking and throws out_of_range exception if needed. much as possible. deque: This is basically a double-ended queue. If we However, just like C++, STL is designed for experienced want to grow/shrink in a vector, we can do it only at one programmers: it requires some expertise to make use of its end. But with deque, we can do it at both the ends. It full potential and there are lots of traps and pitfalls that a provides the same accessing efficiency as the vector but novice can easily fall into. Also, it is a generic library whose the allocation efficiency comparable with a list. design is inspired by the functional programming paradigm: it list: Arrays are optimised for random access but are is not object-oriented! Hence, you need some understanding inefficient when it comes to inserting and deleting and experience about the design philosophy and problem- elements in the middle; so are the vector and deque. For solving approach of STL to make the best use of it. operations requiring intensive insertions and deletions, use a list, which is very efficient for these operations (and is STL components internally implemented as a double-linked list). With a STL consists of three main parts: list, you cannot have random access to the data and so the Containers (like a stack) [] operator is not overloaded. Generic algorithms (like a sort) map and set: Both store the elements along with a Iterators (similar to the use of pointers) unique key. In most of the cases, these two are These components are designed such that they are interchangeable. The only difference is that in a set, the ignorant of specific details of other components, so that values are irrelevant and we keep track of the keys only. they can be combined together as the need arises. Here They provide an important functionality, which the lies the secret of the power of STL: the ability to sequence containers do not provide—the find operation. seamlessly combine the three to fit our need. multimap and multiset: These are extended Containers are objects that can hold other objects. We versions of a map and set respectively. In a map and set, can use any type of object with these containers, but the keys should be unique. But a multimap and multiset do generally, it is assumed that an object that is used with a not have this constraint. All the operations of their container has the following defined for the object: respective counterparts are supported here also. copy constructor assignment operator == operator < operator Algorithms This is because whenever an object is used with a The <algorithm> header file provides us with many of the container, a copy of the object is created and only the copy is algorithms that we use in our day-to-day programming (and present in the container; so we need the copy constructor lots of not so obvious ones, too). For example, most of us and assignment operator to be defined. Also, many of the have ended up writing our own versions of a sort, search, find, algorithms used by the containers need a comparison etc, and STL allows us to reuse the code and helps us to between objects; so we need == and < overloaded operators. concentrate on more creative aspects of programming. Let us look at an example of using a fundamental operation—swap: Containers Containers are the data-structures in which we can store #include <iostream> objects. Basically, we have two kinds of containers: #include <algorithm> Sequence containers: These containers store and using namespace std; retrieve data in a sequential fashion. They include the simple array, list, vector and deque. int main(){ Associative containers: The elements of these string this = “this”, that = “that”; containers are associated in some manner. The std::swap(this, that); associative containers are map, multimap, set and cout<< “this = “<< this<< “and that = “<< that<< endl; multiset. They rely heavily on comparison operators, } because the objects are stored in a sorted order. // prints: this = that and that = this In other words, sequence containers can hold elements of the same type, whereas associative containers are Algorithms in STL are basically of three types: capable of holding a key-value pair. non-modifying (sequence); for example, find Let’s look at a few of the containers in STL: modifying (sequence); for example, fill vector: Vector can be treated as an array with the capability sorted (sequence); for example, sort of growing or shrinking dynamically. This can be safely used Non-modifying algorithms are for read-only/traversing instead of arrays. The elements can be accessed in two ways: functionality that essentially doesn’t modify the content of using the overloaded operator [] the containers. In short, they don’t modify the sequence on using the method at which they operate. Note that ‘sequence’ here refers to the The first one is easier and faster to use, but it is not range ‘sequence containers’—referring to containers with | LINUX FOR YOU | MAY 2007 79
  3. 3. Overview elements of the same type T (homogeneous elements), for int arr[] = {1, 4, 9, 16, 25}; // some values example, std::vector<T>, std::list<T>. int * pos = find(arr, arr+4, 36); Modifying algorithms may alter the sequence on which if(pos == (arr+4)) they operate. The last kind of algorithms work on sorted std::cout<< “Searched element not found in the array”; sequences—for example, the binary_search algorithm. else As you can easily guess, swap comes under modifying std::cout<< “Found in the position “<< sequence algorithms. (pos - arr); // prints: Iterators // Searched element not found in the array Iterators are generalised pointers and act as the glue between containers and algorithms. STL algorithms are written in This aspect of iterators is very important to understand terms of iterator parameters, and STL containers provide as it is used extensively in STL. iterators that can be plugged into algorithms. Generally, iterators point to a location within a container. Why iterators? Iterators have a pointer-like syntax (in many cases, Let’s suppose that you want to go to the beginning of a list. iterators are indeed implemented as pointers internally). You can use the member function front, which returns an Thus, generic algorithms can handle arrays and pointers - iterator (reference) to the first element of the array, and in this is of significant importance since we need not throw this way proceed with your usual work. You might wonder away our C-style arrays for the sake of using this library. why we need iterators when member functions will do. For example, in the find generic algorithm, we can either Let us take the generic algorithm sort, which is used use arrays or container classes: for sorting, say, a vector. If we hadn't had iterators, then we would have had to write a separate algorithm for each #include<iostream> and every container. So we pass to this algorithm two #include<vector> iterators as parameters, which point to the start and end of using namespace std; the sequence to be sorted, respectively. You will notice that, with this mechanism we are able to use any sort of int main(){ containers with an algorithm. int arr[] = {1, 4, 9, 16, 25}; // some values int * arr_pos = find(arr, arr+4, 9); Important concepts for using STL std::cout<< “array pos = “<< arr_pos - arr << endl; Since STL provides a whole new way of solving the // find the first occurrence of 9 in the array problems in C++, there are many concepts that need to be understood to learn and to make best use of STL. vector<int> int_vec; Function objects: Using C style function pointers is for(int i = 1; i <= 5; i++) not type-safe and isn’t object oriented. An alternative in int_vec.push_back(i*i); C++ is to use ‘function objects’. By overloading the vector<int>::iterator vec_pos = function call operator (), we encapsulate a function and find (int_vec.begin(), pass it on to some other functions. The advantages of using int_vec.end(), 9); a function pointer (also referred to as ‘functor’) are: std::cout<< “vector pos = “<< (vec_pos - int_vec.begin()); typesafe and object oriented // find the first occurrence of 9 in the vector efficient, as it can be inlined } reusable, as it can be generic // prints: The idea is to overload the () operator so that the object // array pos = 2 can be used as if it were a function. Overloaded () can have // vector pos = 2 any number of arguments / any return type. For example: Here, note that we are using iterators as ‘pairs’. This is how #include<iostream> we generally make use of iterators: a way of marking the using namespace std; beginning and the end of the sequence to be operated on. However, unlike pointers, there is no iterator equivalent of class printClass{ ‘null’—it’s simply undefined behaviour to dereference an public: iterator pointing to some illegal value. Traditionally, returning template<class T> void operator() (T t) null (0) is how we indicate that a value searched is found or { cout<< t << endl; } not. Since null cannot be used for iterators, how do we indicate }; that the value searched is not found? For that, the element ‘one-past’ the end is used (note that it is not illegal for a pointer template<class T> void print(T type, printClass &p){ to point ‘one-past’ the last element in an array). For example: p(type); // invoke the () operator 80 MAY 2007 | LINUX FOR YOU |
  4. 4. Overview } Adaptors: Adaptors, as the name itself hints, is a component that adapts (modifies) an existing interface of int main(){ a component to expose a different one suitable for some int i = 10; other purpose. There are three types of adaptors: float f = 10.0; Sequence adaptor: The interface of a container is printClass p; exposed in a different way. A classic example for print(i, p); sequence adaptors is from STL itself: stack is built on print(f, p); modifying the interface of deque. } Iterator adaptor: When the interface of an iterator is // prints exposed in a different way, it is an iterator adaptor. // 10 Function adaptor: Function adaptors are function // 10 objects—depending on the function object (say a ‘negator’ or a ‘predicate object’) passed, the behaviour This simple program makes use of function objects to of the algorithm may change. print objects of any type (provided that they override Pseudo-destructor: STL is fully generic and it needs ostream << ()). many extensions/modifications, mostly related to Plug-compatibility: Plug-compatibility in programming templates to support it. For example, ‘pseudo destructor’ jargon means that a generic algorithm and a container can is just a syntactic convenience: it enables primitive type to be plugged (used) together. For example, vector and sort be used with containers and algorithms. are plug-compatible (you can apply sort function on a vector), whereas you cannot use sort for a list—for that template <typename T> void callDest(T &t){ you have to use the sort member function (of list). t.T::~T(); Theoretically, it is possible for generic sort to be plugged }; with list—but it will affect the efficiency of the code. So, list provides a separate member function to achieve that. class Test{ public: sort(vector1.begin(), vector1.end()); ~Test(){ // ok, works std::cout<<“calling the destructor”<<endl; vector1.sort(); } // no sort member function }; sort(list1.begin(), list1.end()); int main(){ // no, generic sort should not be used with list int i; list1.sort(); callDest(i); // ok, works // doesn’t issue compiler error // when t.T::~T() resolves to Nearly containers: STL is a generic library with // this has no effect in the code generated. components written for general-purpose use. But not all components are ‘truly generic’. There are three Test t; components in STL that are written for specific types/ callDest(t); purposes in mind. For example, bitset is not a generic set // results in calling the destructor explicitly component—it is specifically designed to handle bit // prints: information. Such containers are referred to as ‘nearly // calling the destructor containers’, and they are for specific purposes and not } really generic in nature. The other two containers are valarray—designed specifically for numeric Hopefully, this introduction to Standard Template computations, and string, an alternative for null Library would help a novice understand its basics, in detail. terminated C-style strings. We will cover further details on the same topic later. Till Predicate objects: When a function object returns a then, happy reading... Boolean value, it is referred to as a ‘predicate object’. In STL, <functional> contains many such predicate objects and they can be used in generic algorithms to change their behaviour. By: S.G. Ganesh is an engineer in Hewlett-Packard’s C++ For example, the sort method implicitly takes the less<int> compiler team. He has authored a book “Deep C” (ISBN 81- predicate as the third argument (to sort the elements in 7656-501-6). He is also a member of the ANSI/ISO C++ ascending order). To change this default behaviour of sort, it Standardisation committee (JTC1/SC22/WG21), representing is enough to pass some other predicate! HP. You can reach him at | LINUX FOR YOU | MAY 2007 81