Standard Template Library (STL)

Download Report

Transcript Standard Template Library (STL)

The Standard Template Library
•provides the framework for building generic, highly
reusable algorithms and data structures
•A reference implementation of STL has been put
into the public domain by Hewlett-Packard
•Bjarne Stroustrup AT&T : "large, systematic, clean,
formally sound, comprehensible, elegant, and
efficient framework”
•Pamela Seymour Leiden University: "STL looks like
the machine language macro library of an anally
retentive assembly language programmer"
Design goals
•Generality + Efficiency
•Well structured, comprehensive library of useful
components
•Every component is as abstract as theoretically possible and
as efficient as its hand-coded, non-abstract version in C
Alexander Stepanov (BYTE 1995)
The past 25 years have seen attempts to revolutionize programming by
reducing all programs to a single conceptual primitive. Functional
programming, for example, made everything into a function; the
notions of states, addresses, and side effects were taboo. Then, with the
advent of object-oriented programming (OOP), functions became
taboo; everything became an object (with a state).
STL is heavily influenced by both functional programming and OOP.
But it's not a single-paradigm library; rather, it's a library for generalpurpose programming of von Neumann computers.
STL is based on an orthogonal decomposition of component space.
For example, an array and a binary search should not be reduced to a
single, fundamental notion. The two are quite different. An array is a
data structure -- a component that holds data. A binary search is an
algorithm -- a component that performs a computation on data stored in
a data structure. As long as a data structure provides an adequate access
method, you can use the binary-search algorithm on it.
Standard Template Library (STL)

object oriented programming - reuse, reuse, reuse
STL has many reusable components
 Divided into

containers
 iterators
 algorithms


This is only an introduction to STL, a huge class library
STL (Standard Template Library)
A library of class and function templates based on work in generic programming
done by Alex Stepanov and Meng Lee of the Hewlett Packard Laboratories in the
early 1990s. It has three components:
1. Containers: Generic "off-the-shelf" class templates for storing
collections of data
2. Algorithms: Generic "off-the-shelf" function templates for operating
on containers
3. Iterators: Generalized "smart" pointers that allow algorithms to
operate on almost any container
Iterators
begin()
end()
Container Classes
vector
Algorithms
sort()
Standard Template Library (STL)
vector
algorithms
containers
sort()
iterators
function libraries
class libraries
begin()
end()
class
templates
function
templates
classes
overloaded
functions
user-defined
(enums, structs, etc.)
specific functions
data types
inline Code
Data
+
Algorithms
The Evolution of Reusability/Genericity
= Programs
Containers, Iterators, Algorithms
Algorithms use iterators to interact with objects
stored in containers
Container
Container
Iterator
Algorithm
Iterator
Objects
Iterator
Algorithm
Algorithm
Iterator
STL's Containers
In 1994, STL was adopted as a standard part of C++.
There are 10 containers in STL:
Kind of Container
STL Containers
Sequential:
deque, list, vector
Associative:
map, multimap, multiset, set
Adapters:
priority_queue, queue, stack
Non-STL:
bitset, valarray, string
Organizacja STL (2)
Organizacja STL (3)
Organizacja STL (4)
Organizacja STL (5)
Organizacja STL (6)
vector
Operations
Constructors:
vector<T> v,
v1(100),
v2(100, val),
v3(fptr,lptr);
Copy constructor
Destructor
v.capacity()
v.max_size()
v.size()
v.reserve(n)
v.empty()
v.push_back(val)
v.pop_back()
v.front(), v.back(),
v[i], v.at(i)
Relational operators
Assignment (=)
v.swap(v1)
//
//
//
//
//
empty vector
contains 100 elements of type T
contains 100 copies of val
contains copies of elements in
memory locations fptr up to lptr
Number of elements v can contain without growing
Upper limit on the size and capacity
Number of elements v actually contains
Increase capacity (but not size) to n
Check if v is empty
Add val at end
Remove value at end
Access first value, last value,
i-th value without / with range checking
(at throws out-of-range exception)
Lexicographic order is used
e.g., v1 = v2;
Swap contents with those of vector v1
Iterators
•Iterators are similar to pointers
–point to first element in a container
–iterator operators uniform for all containers
•* dereferences, ++ points to next element
•begin() returns iterator pointing to first element
•end() returns iterator pointing to last element
–use iterators with sequences (ranges)
•containers
•input sequences - istream_iterator
•output sequences - ostream_iterator
Iterators


Iterators are pointer-like entities that are used to
access individual elements in a container.
Often they are used to move sequentially from
element to element, a process called iterating
through a container.
vector<int>
array_
17
vector<int>::iterator
4
23
12
size_
The iterator corresponding to
the class vector<int> is of
the type vector<int>::iterator
Iterators – generalized pointers
The other operations require knowledge of iterators. For example:
v.begin()
Returns iterator positioned at first element
v.end()
Returns iterator positioned immediately after last element
v.insert(it, val)
Inserts val at position specified by iterator it
v.erase(it)
Removes the element at position specified by iterator it
Note: insert() moves all the elements from position it and following one position
to the right to make room for the new one. erase() moves all the elements
from position it and following one position to the left to close the gap.
An iterator declaration for vectors has the form:
vector<T>::iterator it;
Example: Function to display the values stored in a vector of doubles:
template<typename T>
T
ostream & operator<<(ostream & out, const vector<double> & v)
{
for (int i = 0; i < v.size(); i++)
out << v[i] << " ";
return out;
}
or using an iterator:
T
for (vector<double>::iterator it = v.begin();
it != v.end(); it++)
out << *it << " ";
Go to 54
Przykład – vector (1)
Przykład – vector (2)
Przykład – vector (3)
Przykład – vector (4)
Przykład – vector (5)
Przykład – vector (6)
Przykład – vector (7)
vector inefficiences
• When its capacity must be increased,
 it must copy all the objects from the old vector to the new vector.
 it must destroy each object in the old vector.
 a lot of overhead!
• With deque this copying, creating, and destroying is avoided.
• Once an object is constructed, it can stay in the same memory locations
as long as it exists (if insertions and deletions take place at the ends of the
deque).
• Unlike vectors, a deque is not stored in a single varying-sized block
of memory, but rather in a collection of fixed-size blocks (typically, 4K
bytes).
• One of its data members is essentially an array map whose elements
point to the locations of these blocks.
STL’s stack container
STL includes a stack container.
Actually, it is an adapter, as indicated by the fact that one of its
type parameters is a container type.
Sample declaration:
stack<int, vector<int> > st;
Basically, it is a class that acts as a wrapper around another class,
providing a new user interface for that class.
A container adapter such as stack uses the members of the
encapsulated container to implement what looks like a new container.
For a stack<T, C<T> >, C<T> may be any container that
supports push_back() and pop_back() in a LIFO manner.
In particular C may be a vector, a deque, or a list.
Basic Operations
Constructor
Note 1:
stack< T, C<T> > st; creates an empty stack st of
elements of type T; it uses a container C<T> to store the
elements.
The space between the two >s must be there to avoid
confusing the compiler (else it treats it as >>); for example,
stack< int, vector<int> > s;
not stack< int, vector<int>> s;
Note 2: The default container is deque; that is, if C<T> is omitted
as in stack<T> st; a deque<T> will be used
to store the stack elements. Thus stack<T> st; is
equivalent to stack< T, deque<T> > st;
Destructor
Assignment, relational Operators
size(), empty(), top(), push(), pop()
STL's queue container
In queue<T, C<T> >, container type C may be list or deque.
Why not vector? You can't remove from the front efficiently!
The default container is deque.
queue has same member functions and operations as stack except:
push() adds item at back (our addQ())
front() (instead of top()) retrieves front item
pop() removes front item (our removeQ())
back() retrieves rear item
queue Example
#include <string>
#include <queue>
using namespace std;
int main()
{
queue<int>
qint;
queue<string> qstr;
// Output number of values stored in qint
cout << qint.size() << endl;
for (int i = 1; i <= 4; i++)
qint.push(2*i);
qint.push(123);
cout << qint.size() << endl;
Contd.
while (!qint.empty())// Dump contents of qint
{
cout << qint.front() << " ";
qint.pop();
}
cout << endl;
qstr.push("STL is"); qstr.push("impressive!\n");
while (!qstr.empty())
{
cout << qstr.front() << ' ';
qstr.pop();
}
}
Output:
0
5
2 4 6 8 123
STL is impressive!
Deques
As an ADT, a deque — an abbreviation for double-ended queue — is a sequential
container that functions like a queue (or a stack) on both ends.
It is an ordered collection of data items with the property that
items can be added and removed only at the ends.
Basic operations are:
Construct a deque (usually empty):
Check if the deque is empty
Push_front:
Add an element at the front of the deque
Push_back:
Add an element at the back of the deque
Front:
Retrieve the element at the front of the deque
Back:
Retrieve the element at the back of the deque
Pop_front:
Remove the element at the front of the deque
Pop_back:
Remove the element at the back of the deque
STL's deque Class Template
Has the same operations as vector<T> except that there is no capacity()
and no reserve()
Has two new operations:
d.push_front(value); Push copy of value at front of d
d.pop_front(value);
Remove value at the front of d
Like STL's vector, it has several operations that are not defined for deque as
an ADT:
[]
insert and delete at arbitrary points in the list,
same kind of iterators.
But insertion and deletion are not efficient and, in fact, take longer than for
vectors.
vector vs. deque
Capacity of a vector must be increased
 it must copy the objects from the old vector to the new
vector
 it must destroy each object in the old vector
 a lot of overhead!
With deque this copying, creating, and destroying is avoided.
Once an object is constructed, it can stay in the same memory
locations as long as it exists (if insertions and deletions
take place at the ends of the deque).
Unlike vectors, a deque isn't stored in a single varying-sized
block of memory, but rather in a collection of fixed-size blocks
(typically, 4K bytes).
One of its data members is essentially an array map whose elements
point to the locations of these blocks.
Algorithms
•Before STL
–class libraries were incompatible among vendors
–algorithms built into container classes
•STL separates containers and algorithms
–easier to add new algorithms
–more efficient, avoids virtual function calls
•STL provides algorithms used generically across containers
–operate on elements indirectly through iterators
–often operate on sequences of elements defined by pairs of
iterators
–algorithms often return iterators, such as find()
–premade algorithms save programmers time and effort
STL algorithms
do not access containers directly
stand-alone functions that operate on data by means of iterators
can work with regular C-style arrays as well as containers.
#include <iostream>
#include <algorithm>
using namespace std;
// Add our Display() template for arrays
int main()
{
int ints[] = {555, 33, 444, 22, 222, 777, 1, 66};
// must supply start and "past-the-end" pointers
sort(ints, ints + 8);
cout << "Sorted list of integers:\n";
Display(Ints, 8);
STL's algorithms (§7.5)
Another major part of STL is its collection of more than 80 generic algorithms.
They are not member functions of STL's container classes and do not access
containers directly. Rather they are stand-alone functions that operate on data by
means of iterators . This makes it possible to work with regular C-style arrays as
well as containers. We illustrate one of these algorithms here: sort.
Sort 1: Using <
#include <iostream>
#include <algorithm>
using namespace std;
template <typename ElemType>
void Display(ElemType arr, int n)
{
for (int i = 0; i < n; i++)
cout << arr[i] << " ";
cout << endl;
}
// Add a Display() template for arrays
int main()
{
int ints[] = {555, 33, 444, 22, 222, 777, 1, 66};
// must supply start and "past-the-end" pointers
sort(ints, ints + 8);
cout << "Sorted list of integers:\n";
Display(Ints, 8);
double dubs[] = {55.5, 3.3, 44.4, 2.2, 22.2, 77.7, 0.1};
sort(dubs, dubs + 7);
cout << "\nSorted list of doubles:\n";
Display(Dubs, 7);
string strs[] = {"good","morning","cpsc","186","class"};
sort(strs, strs + 5);
cout << "\nSorted list of strings:\n";
Display(strs, 5);
}
Output:
Sorted list of integers:
1 22 33 66 222 444 555
Sorted list of doubles:
0.1 2.2 3.3 22.2 44.4
777
55.5
Sorted list of strings:
186 class cpsc good morning
77.7
Sorting a vector of stacks using < (defined for stacks)
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
#include "StackT.h"
/* Add operator<() to our Stack class template as a member
function with one Stack operand or as a friend function with
two Stacks as operands.
Or because of how we're defining < for Stacks here,
st1 < st2
if
top of st1 < top of st2
we can use the top() access function and make operator<()
an ordinary function */
template <typename StackElement>
bool operator<(const Stack<StackElement> & a,
const Stack<StackElement> & b)
{ return a.top() < b.top();}
int main()
{
vector< Stack<int> > st(4);
// vector of 4 stacks of ints
st[0].push(10); st[0].push(20);
st[1].push(30);
st[2].push(50); st[2].push(60);
st[3].push(1); st[3].push(999);
sort(st.begin(), st.end());
for (int i = 0; i < 4; i++)
{
cout << "Stack " << i << ":\n";
st[i].display();
cout << endl;
}
}
Output
st[3].push(3);
Stack 0:
3
999
1
Stack 1:
20
10
Stack 2:
30
Stack 3:
60
50
For_Each() Algorithm
#include <vector>
#include <algorithm>
#include <iostream>
void show(int n)
{
cout << n << ” ”;
}
int arr[] = { 12, 3, 17, 8 }; // standard C array
vector<int> v(arr, arr+4); // initialize vector with C array
for_each (v.begin(), v.end(), show); // apply function show
// to each element of vector v
Function Objects

function objects- contain functions invoked off the
object using operator()
 header <functional>
STL function objects
Type
divides< T >
arithmetic
equal_to< T >
relational
greater< T >
relational
greater_equal< T > relational
less< T >
relational
less_equal< T >
relational
logical_and< T >
logical
logical_not< T >
logical
logical_or< T >
logical
minus< T >
arithmetic
modulus< T >
arithmetic
negate< T >
arithmetic
not_equal_to< T > relational
plus< T >
arithmetic
multiplies< T >
arithmetic
Functions Objects
Some algorithms like sort, merge, accumulate can take a
function object as argument.

A function object is an object of a template class that has a
single member function : the overloaded operator ()

It is also possible to use user-written functions in place of
pre-defined function objects
#include <list>
#include <functional>
int arr1[]= { 6, 4, 9, 1, 7 };
list<int> l1(arr1, arr1+5); // initialize l1 with arr1
l1.sort(greater<int>()); // uses function object greater<int>
// for sorting in reverse order l1 = { 9, 7, 6, 4, 1 }

Function Objects

The accumulate algorithm accumulates data over the
elements of the containing, for example computing the
sum of elements
#include <list>
#include <functional>
#include <numeric>
int arr1[]= { 6, 4, 9, 1, 7 };
list<int> l1(arr1, arr1+5); // initialize l1 with arr1
int sum = accumulate(l1.begin(), l1.end() , 0, plus<int>());
int sum = accumulate(l1.begin(), l1.end(),0); // equivalent
int fac = accumulate(l1.begin(), l1.end() , 0, times<int>());
User Defined Function Objects
class squared _sum // user-defined function object
{
public:
int operator()(int n1, int n2) { return n1+n2*n2; }
};
int sq = accumulate(l1.begin(), l1.end() , 0, squared_sum() );
// computes the sum of squares
User Defined Function Objects
template <class T>
class squared _sum // user-defined function object
{
public:
T operator()(T n1, T n2) { return n1+n2*n2; }
};
vector<complex> vc;
complex sum_vc;
vc.push_back(complex(2,3));
vc.push_back(complex(1,5));
vc.push_back(complex(-2,4));
sum_vc = accumulate(vc.begin(), vc.end() ,
complex(0,0) , squared_sum<complex>() );
// computes the sum of squares of a vector of complex numbers
Standard C++
Exceptions (1)
Standard C++
Exceptions (2)
Standard C++
Exceptions (3)
Standard C++
Exceptions (4)