Professional Documents
Culture Documents
Overview
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.
CMYK
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
CMYK
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
CMYK
Overview
CMYK