Quizzes - Ramapo

advertisement
C++ Training
Datascope
Lawrence D’Antonio
Lecture 10
An Overview of C++:
The Standard Template Library
Why Should You Learn STL?
 STL is generic. It involves data structures
and algorithms that are designed to work
on as wide a range of data types as
possible.
 STL is useful. It provides a variety of basic
tools that are easy to learn and to use.
STL has a well-designed architecture that
provides a variety of algorithms that can
manipulate a number of data structures.
Why Should You Learn STL?
 STL is efficient. STL algorithms come with
performance guarantees. For example, insertion
into a map data structure is guaranteed to be at
most logarithmic.
 STL is extensible.The components of STL may
be put together to create powerful generic
libraries. For example, there exists an MTL
(Matrix Template Library), a GTL (Graph
Template Library), and Regex++, a regular
expression library based on STL.
What is STL?
 The Standard Template Library (STL) is a
powerful collection of generic data
structures and algorithms that is part of the
standard library in C++. The algorithms in
STL are orthogonal to the data structures,
in the sense that algorithms are designed
to work without having to know details of
the data structures to which they are being
applied.
What is STL? 2
 In order for this process to work, data
containers are required to define the
concept of an iterator (i.e., objects that
define an addressing mechanism for the
data structure). These iterators are used in
turn by the STL algorithms to access the
data structure.
What is STL? 3
 Different algorithms require different types
of access.
 For example, the generic sorting
algorithms in the STL require random
access. This restricts the data structures
that sorting algorithms can be used with to
ones that provide random access (in the
standard library this includes arrays,
strings, vectors, and deques).
What is STL? 4
 Alexander Stepanov, the primary




developer of the STL, identifies four
principles that underlie the design of STL.
Generic programming
Abstractness without loss of efficiency
Von Neumann computational model
Value semantics
Generic programming
 Generic programming can be thought of
as writing software components that can
be used for as wide a range of types as
possible.
 Stepanov states that generic programming
attempts to find the most abstract form of
an efficient algorithm.
Generic programming 2
 The central abstraction in STL is that of the
concept. A concept is a set of requirements for
data types.
 For example, a Sequence is a concept
describing data containers that store elements in
a linearly ordered range and allow for insertion
or deletion at any point in that range.
 Any data structure fitting these requirements is a
model for the Sequence concept. STL defines
three sequence types; vectors, lists, and
deques.
Generic programming 3
 Concepts can be classified and organized
in hierarchies. For example, one of the
primary concepts of the STL is that of the
Iterator. Iteration allows for movement
from one address location in a data
structure to another.
 There are various categories of Iterators.
Generic programming 4
 A ForwardIterator only allows movement in
one direction. There are two Iterator
concepts that the ForwardIterator refines,
the InputIterator and the OutputIterator.
 The InputIterator can only read from the
current location and allows movement
forward. The OutputIterator can only write
to the current location and allows
movement forward.
Generic programming 5
 The algorithms that form the STL are
themselves organized around concepts.
 A generic algorithm consists of an
implementation and the set of
requirements that its arguments must
satisfy.
 For example, the STL algorithm reverse()
will reverse the elements of any container
that is a model of the Sequence concept.
Generic programming 6
 Here is a non-generic gcd function.
int gcd(int x, int y)
{
while (y != 0) {
int t = x % y;
x = y;
y = t;
}
return x < 0 ? -x : x;
}
Generic programming 7
 This algorithm is fine as it goes, but a
generic version should be valid for other
algebraic quantities besides integers (in
fact, for any principal ideal domain). For
example, we would want to extend the
algorithm to polynomials and Gaussian
integers.
Generic programming 8
 One problem arises here, the return
statement, which is assuming that the gcd
returns a positive value, will only be valid
for types that satisfy the requirement of
being totally ordered.
Generic programming 9
 Here is a generic gcd function.
template <class T>
T gcd(T x, T y)
{
while (y != 0) {
T t = x % y;
x = y;
y = t;
}
return x;
}
Generic programming 10
 In this case, the 'greatest' divisor that we
are returning is only unique up to
multiplication by a unit. Each type will have
its own concept of greatest (greatest
degree for polynomials, greatest modulus
for Gaussian integers).
Generic programming 11
 To summarize (and perhaps oversimplify).
 object-oriented programming = data
abstraction + object types + type inheritance
 generic programming = data abstraction +
generic types + concept refinement
Abstraction
 STL makes efficiency an important part of the
design of the library.
 Complexity guarantees are part of interface of
each STL component.
 For example, there are three sequence
containers, vector<Type>, list<Type>,
deque<Type>.
 The C++ standard gives the following time
guarantees for element access, element
insert/delete, and range insert/delete.
Abstraction 2
Operation
Vector
Deque
List
Access at front
Constant
Constant
Constant
Access at back
Constant
Constant
Constant
Random access Constant
Constant
Linear
Insert at front
Linear
Constant*
Constant
Insert at back
Constant*
Constant*
Constant
Random insert
Linear
Linear
Constant
Insert range
Linear
Linear
Constant
Abstraction 3
 STL also provides associative containers that, in




general, store elements of the form (key, value), in
some sort of tree structure (usually a red-black tree).
There are four types of associative containers:
Sets (which are collections of unique keys without
corresponding values).
Multisets (which allow for multiple occurrences of a
key).
Maps (which store key, value pairs with keys being
unique).
Multisets (which store key, value pairs with multiple
keys possible).
Abstraction 4
 The basic operations for associative
containers are, finding an element with a
given key, inserting an element, erasing an
element, erasing all elements pointed to
by a key.
 In the following table, N represents the
number of elements in the container, K
represents the number of values
corresponding to a particular key.
Abstraction 5
Operation Set
Multiset
Map
Multimap
Find
Log(N)
Log(N)
Log(N)
Log(N)
Insert
Log(N)
Log(N)
Log(N)
Log(N)
Erase
Constant*
Constant*
Constant*
Constant*
Log(N)+K
Log(N)
Log(N)+K
Erase Key Log(N)
Von Neumann Model
 Stepanov notes the significance of
addressing in the design of STL.
 The STL containers provide services for
adding or deleting addresses to a data
structure. Iterators can be seen as moving
from one address to another in a
container.
Value Semantics
 In the STL containers own their elements.
When a container is copied, all elements
are copied. When a container is
destroyed, all objects it contains are in turn
destroyed.
 All copies in STL are deep copies.
 These value semantics imply that STL
containers can never overlap.
Value Semantics 2
 Of course, for the sake of efficiency, one
can store pointers to larger structures in a
container.
 But this itself presents problems. One has
to adapt the comparison functions that
several STL containers and algorithms
require to work with pointers.
Value Semantics 3
 A more important consideration is the use
of STL with polymorphic objects.
 Because of the use of value semantics in
STL, polymorphic objects are either sliced
(i.e., only their base parts are copied or
assigned) or, if pointers are used, there is
a problem of ownership of the object (e.g.,
what should happen if the object is
removed from the container).
Value Semantics 4
 One solution to this problem is the use a
type of smart pointer.
 For example, one can define a pointer
object containing a reference to a
polymorphic object.
 When copying or assigning the smart
pointer, a new copy of the referenced
object is made (with the correct dynamic
type).
A Short History of STL
 The first explorations of the concept of generic
programming go back to work of Alexander
Stepanov in the late '70s.
 Later work at General Electric Research and
Development in collaboration with David Musser
led to the development of a list processing
library in Ada, the first language to support
generic programming.
 This work, in 1987, was followed by additional
work in Scheme
A Short History of STL 2
 Stepanov, in work at Bell Laboratories and then
later at Hewlett-Packard Research Laboratories,
turned his attention to formulating generic
algorithms in C++.
 He was particularly attracted to the C++ feature
of templates, which allow for parametrized
types.
 Bjarne Stroustrup, the developer of C++,
introduced templates in 1991, in the cfront
Release 3.0
A Short History of STL 3
 While Stepanov was at Hewlett-Packard, Meng
Lee joined his project and became a major
contributor to the library that was eventually
called STL.
 Andrew Koenig of Bell Laboratories, a member
of the X3J16 ANSI/ISO committee for C++
standardization, invited Stepanov to present the
basic ideas of the library at the November 1993
X3J16 meeting.
 This led to request from the committee for
Stepanov and Lee to write a draft proposal for
STL at the March 1994 committee meeting.
A Short History of STL 4
 Further revisions and extensions were proposed
to the STL at this point.
 The major extension, associative containers,
was implemented by David Musser.
 After this work, the STL proposal was accepted
by the ANSI committee at their July 1994
meeting.
 The document produced by Stepanov and Lee
was accepted into the X3J16 draft standard.
A Short History of STL 5
 The dissemination of the STL became
widespread with the decision by HP, in
August 1994, to make the library freely
available on the Internet.
 This implementation, due primarily to
Stepanov, Lee, and Musser, is the basis
for all future versions of the STL.
A Short History of STL 6
 In 1996 Stepanov joined SGI and together with
Matthew Austern and Hans Boehm, worked on
an implementation of the STL.
 This implementation includes various extensions
of the STL, such as thread-safe memory
allocation and hash tables.
 It should be noted that the extensions in the SGI
version of the library have not yet been accepted
into the C++ standard.
 This implementation may be downloaded,
together with extensive documentation on the
library, at http://www.sgi.com/tech/stl/
STL by example
 First, to see the power of STL and how it
functions let us look at a simple series of
examples, adapted from David Harvey's
online STL tutorial:
http://www.davethehat.com/articles/eff_stl.
htm
STL by example 2
 Word Copy Example
 The task is to write a function that reads in
strings from an input stream, sorts them,
eliminates duplicates, and then prints the
results to an output stream, one word per
line.
STL by example 3
 Version 1 (Non-STL)
 This version is given in pseudo-code to
spare the reader the gory details (which
they can presumably fill in for
themselves).
STL by example 4
ostream& wordcopy(istream &in, ostream &out)
{
string s; //string to be read
//Also need a container to store the strings
while( !in.eof() && in >> s ) {
//store s in container
}
//Sort the container in alphabetical order
//Remove duplicates, this gets ugly if you used an array
//Print each string to output stream, one per line
return out;
}
STL by example 5
 Version 2 (STL using vector container)
ostream& wordcopy(istream &in, ostream&out)
{
string s; //string to be read
vector<string> v;
//STL vector container for the strings
while( !in.eof() && in >> s )
v.push_back(s);
//inserts s at end of container
STL by example 6
//STL sort algorithm
sort(v.begin(), v.end());
//Use the STL unique() to 'eliminate‘ duplicates
//unique 'removes' consecutive duplicates
vector<string>::iterator p =
unique(v.begin(), v.end());
//Now send results to output
for(vector<string>::iterator i = v.begin(); i != p; i++)
out << *i << '\n';
return out;
}
STL by example 7
 A couple of comments on this version.
 The use of iterator is an essential part of
STL. Iterators are used to traverse
containers, and to add or remove items
from containers.
 Each container-type has a corresponding
iterator-type. Vectors use random-access
iterators.
STL by example 8
 The unique algorithm has a quirk that one must
get used to.
 Since it is a generic algorithm, and hence knows
nothing about the underlying organization of the
data it is being applied to, it cannot actually
remove duplicates from the container.
 What it in fact does is to place any duplicates at
the end of the container. After the algorithm is
completed, there will be a range of nonduplicates, say in positions [first,last). The
function will return position last.
unique() algorithm
template<class FwdIt>
FwdIt unique(FwdIt F, FwdIt L)
{
FwdIt X = F; //X will step through duplicates
FwdIt Fb = F; //Fb will store position of first duplicate
for( *X++ = *Fb; ++F != L; ) {
if( !(*Fb == *F) ) {
Fb = F;
*X++ = *Fb;
}
}
return X;
}
unique() algorithm 2
main() {
int A[ ] = {1,1,1,2,3,3};
int *p = std::unique(&A[0],&A[6]);
for(int *q = &A[0]; q != p; q++)
std::cout << *q << ' ';
std::cout << '\n';
return 0;
}
unique() algorithm 3
template<class FwdIt, class BinPred>
FwdIt unique(FwdIt F, FwdIt L, BinPred P)
{
FwdIt X = F;
FwdIt Fb = F;
for( *X++ = *Fb; ++F != L; ) {
if( !P(*Fb,*F) ) {
Fb = F;
*X++ = *Fb;
}
}
return X;
}
unique() algorithm 4
 Consider the following predicate
class P {
public:
bool operator()(int x, int y) {
return ((x % 2) != (y%2));
}
};
unique() algorithm 5
main() {
int A[ ] = {1,1,1,2,3,3};
int *p = unique(&A[0],&A[6],P());
for(int *q = &A[0]; q != p; q++)
std::cout << *q << ' ';
std::cout << '\n';
return 0;
}
STL by example 9
 Version 3 (STL using set container)
 A student studying STL quickly learns
about the benefits of the STL
associative containers.
 For the task at hand, the set container
is particularly useful. Data in a set is
kept in sorted order, and no duplicates
are allowed. This is exactly what we
want.
STL by example 10
ostream& wordcopy(istream &in, ostream &out)
{
string s; //string to be read
set<string> words; //STL set container for the strings
while( !in.eof() && in >> s )
words.insert(s); //Insert in sorted order
STL by example 11
//Now send results to output
for(set<string>::iterator i = words.begin();
i != words.end(); i++)
out << *i << '\n';
return out;
}
STL by example 12
 Note, if the input string s is already in set,
then the insertion does nothing.
 The insert function returns a pair
consisting of an iterator and a bool.
 If the insertion was successful, it returns
(new position, true).
 If the insertion failed, because the value
was already in the set, the return will be
(existing position, false).
STL by example 13
 Version 4 (STL using sets and stream
adaptors)
 Copying operations in the STL often make
use of adaptors. An adaptor makes one
object act like another.
 A stream adaptor makes an input or output
stream look like a container to an STL
algorithm.
 In general, the copy algorithms in the library
use source and destination containers. But
by using adaptors, we can copy from or to a
stream.
STL by example 14
 One difficulty in using the copy algorithms
is the fact that the destination container is
assumed to have the space to hold the
data copied over from the source.
 If this is not the case, as in the example
below, then an inserter object must be
used for the destination (the inserter will
call the underlying insert() member
function).
STL by example 15
ostream& wordcopy(istream &in, ostream &out)
{
set<string> words;
//STL set container for the strings
//Read in from istream and store in set
copy(istream_iterator<string>(in),
istream_iterator<string>(),
inserter(words, words.begin()));
STL by example 16
//Now send results to output
copy(words.begin(), words.end(),
ostream_iterator<string>(out, "\n"));
return out;
}
STL by example 17
 A few comments are in order.
 The adaptor, istream_iterator, needs to know the
data type that is being read, string in this case.
 Note that the extraction operator >> is used by
istream_iterator, so it can only read types for
which this operator has been defined.
 Also, we have used a constructor to create the
istream_iterator and to give it the input stream to
read from.
STL by example 18
 The default constructor for istream_iterator is
used to create an end of file position that is used
to terminate the algorithm.
 The mechanism to make this work is a little
tricky, since the default istream_iterator doesn't
know what file it is supposed to be the end of!
 Here is the way it works. Istream iterators keep a
data member that is a pointer, lets call it Istr, to
the istream it traverses.
STL by example 19
 Suppose we declare (note the string type
plays no role) two istream iterators and
then increment one of them.
istream_iterator<string> i(in_file);
//i.Istr = &in_file
istream_iterator<string> j;
//j.Istr = 0
++i;
STL by example 20
 The increment operator for i calls an
internal read function that uses the
extraction operator >>.
 If the extraction fails, i.Istr is set equal to 0,
and then iterators i, j will compare as being
equal.
STL by example 21
 A third comment on the above version is
that the ostream_iterator constructor takes
two arguments, the ostream and a string
to be used as a delimiter between outputs.
Iterator adaptors
 Let’s look in more detail at the iterator
adaptors istream_iterator,
ostream_iterator,
insert_iterator (which inserter
returns).
istream_iterator
template<class T, class E = char,
class Tr = std::char_traits<E> >
class istream_iterator {
public:
typedef istream_iterator<T,E,Tr> Iter;
typedef E char_type;
typedef Tr traits_type;
typedef std::basic_istream<E,Tr> istream_type;
istream_iterator 2
protected:
T val;
istream_type *Istr;
void Getval() {
if (Istr != 0 && !(*Istr >> val))
Istr = 0;
}
istream_iterator 3
public:
istream_iterator()
: Istr(0) {}
istream_iterator(istream_type &I)
: Istr(&I) { Getval(); }
const T& operator*() const
{ return val; }
const T* operator->() const
{ return &**this; }
Iter &operator++()
{ Getval(); return *this; }
Iter operator++(int)
{ Iter temp; Getval(); return temp; }
istream_iterator 4
bool Equal(const Iter& x) const
{ return Istr == x.Istr; }
};
template<class T, class E, class Tr>
bool operator==(const istream_iterator<T,E,Tr> &x,
const istream_iterator<T,E,Tr> &y)
{ return x.Equal(y); }
template<class T, class E, class Tr>
bool operator!=(const istream_iterator<T,E,Tr> &x,
const istream_iterator<T,E,Tr> &y)
{ return !(x == y); }
ostream_iterator
template<class T, class E = char,
class Tr = std::char_traits<E> >
class ostream_iterator {
public:
typedef ostream_iterator<T,E,Tr> Iter;
typedef T value_type;
typedef E char_type;
typedef Tr traits_type;
typedef std::basic_ostream<E,Tr> ostream_type;
protected:
const E *Delim;
ostream_type *Ostr;
ostream_iterator 2
public:
ostream_iterator(ostream_type &O, const E *D = 0)
: Ostr(&O), Delim(D) { }
Iter &operator=(const T&x)
{ *Ostr << x;
if (Delim != 0)
*Ostr << Delim;
}
ostream_iterator 3
const T& operator*() const
{ return *this; }
Iter &operator++()
{ return *this; }
Iter operator++(int)
{ return *this; }
};
insert_iterator
template<class C>
class insert_iterator {
public:
typedef C container_type;
typedef typename C::reference reference_type;
typedef typename C::value_type value_type;
protected:
C *container;
typename C::iterator iter;
insert_iterator 2
public:
insert_iterator(C &X, typename C::iterator I)
:container(&X), iter(I) {}
insert_iterator<C>& operator=(
typename C::const_reference val)
{ iter = container->insert(iter,val);
++iter;
return *this;
}
insert_iterator 3
insert_iterator<C>& operator*()
{ return *this; }
insert_iterator<C>& operator++()
{ return *this; }
insert_iterator<C>& operator++(int)
{ return *this; }
};
template<class C,class Iter>
insert_iterator<C> inserter(C& X, Iter I)
{
return insert_iterator<C>(X, C::iterator(I));
}
STL by example 22
 Version 5 (STL using transform() for string
conversion)
 The problem of sorting strings is
complicated by the issue of case. The
versions above are case-sensitive (so "The"
and "the" would both be in the output).
 A simple way to handle is to convert the
strings to lower case as they are being read.
But we would like to do this while keeping
the simplicity of version 4.
STL by example 23
 This is where the transform algorithm
comes into play. This function will
apply a function (or function object), to
each element in a source container, and
pass the return value of this function to
the destination container.
STL by example 24
ostream& wordcopy(istream &in, ostream &out)
{
set<string> words;
//STL set container for the strings
//Read in from istream, convert to lower case,
//Store in set
transform(istream_iterator<string>(in),
istream_iterator(),
inserter(words, words.begin()),
to_lower);
STL by example 25
//Now send results to output
copy(words.begin(), words.end(),
ostream_iterator<string>(out, "\n"));
return out;
}
STL by example 26
 Here is the function to_lower
string to_lower(const string &s)
{
string temp(s.size(),0);
for(int i = 0; i < s.size(); i++)
temp[i] = tolower(s[i]);
return temp;
}
STL by example 27
 Version 6 (STL with a different sorting
criterion)
 In this version we want the strings sorted
according to the following criterion.
 The strings should be printed out
according to order of their word length. If
two strings are the same length, then print
out in alphabetical order.
STL by example 28
 To accomplish this we must give the set
container a comparison function object.
 A function object (called a functor) is an
object with an overloaded function call
operator.
STL by example 29
struct lengthcomp {
bool operator() (const string &s1, const string &s2)
const
{
return
( s1.size() < s2.size() ) ||
( (s1.size() == s2.size()) && (s1 < s2) );
}
};
STL by example 30
 The only other change we make is:
set<string,lengthcomp> words;
How Much C++ Do You Need to
Know for STL?
 Template Metaprogramming
 Templates can be viewed as an interpreted
programming language. For example, consider
the following example:
template<int N>
struct Factorial {
enum { value = N * Factorial<N-1>::value };
};
How Much …? 2
//Specialized version
template <>
struct Factorial<1> {
enum { value = 1 };
};
//...
cout << '5!= ' << Factorial<5>::value;
How Much …? 3
 Traits classes
 Traits are a method for associating information
about related types, values and functions with a
template parameter type.
 Traits are used in several parts of the STL, but
especially with iterators.
 Consider an example from the Nathan Myers
paper that introduced the concept of traits to the
C++ community.
How Much …? 4
 Myers invented traits to handle a certain
problem with the C++ I/O library.
 The C I/O library is meant to work with the char
type. But C++ is meant to be a reusable,
extensible language.
 So that the design of the iostream library should,
as far as possible, support the extension of the
I/O routines to generic character types (different
character sets, different size character types,
etc.).
How Much …? 5
 Consider the streambuf class, which is the
central class in the iostream library. In the
original version of C++, streambuf was defined
in the form:
class streambuf {
int sgetc(); //return the next character or EOF
int sgetn(char*, int N); //get N characters
};
How Much …? 6
 Suppose we want to parametrize this class
with respect to character type.
 We have a problem with the return type of
sgetc(). If we are using a different
character type, then we may need a
different type to represent EOF.
 One solution is to also make the return
type of sgetc() a type parameter.
How Much …? 7
template<class charT, class intT>
class basic_stream_buf {
intT sgetc();
int sgetn(charT*, int N);
};
How Much …? 8
 This has two problems.
 First of all it is annoying for the user to
have to remember the type of the end-offile marker.
 Second, and perhaps more important, is
the question of how sgetc() should be
written.
 What should it actually return in the case
that the end of file is found?
How Much …? 9
 The traits technique works as follows.
 One defines a character traits class, which
gives the properties (i.e., the traits) for
each character type for which we want to
use the iostream library.
How Much …? 10
 One defines the default traits class,
template<class charT>
struct ios_char_traits { };
 The default traits class is empty because
what are the traits of an arbitrary character
type?
 One can specialize this class for specific
character types.
How Much …? 11
 Here is the specialized version for char.
struct ios_char_traits<char> {
typedef char char_type;
typedef int int_type;
static inline int_type eof() { return EOF; }
};
How Much …? 12
 Here is the specialized version for wide
char.
struct ios_char_traits<wchar_t> {
typedef wchar_t char_type;
typedef wint_t int_type;
static inline int_type eof() { return WEOF; }
};
How Much …? 13
 Here is the revised streambuf class.
template <class charT> class basic_streambuf {
public:
typedef ios_char_traits<charT> traits_type;
typedef traits_type::int_type int_type;
int_type eof() { return traits_type::eof(); }
int_type sgetc();
int_type sbumpc(); int_type snextc();
int sgetn(charT*, int N);
};
A Short Tour of STL









The components of STL
Concepts
Iterators
Iterator Adaptors
Containers
Container Adaptors
Algorithms
Functors
Allocators
Basic Concepts
 Assignable
 Concept: A type is Assignable if it allows
for copying objects of that type and for
assigning values to variables of that type.
 Operations: copy constructor and
operator=
 Models: All built-in types and STL
containers, except for const types.
Basic Concepts 2
 Default Constructible
 Concept: A type is Default Constructible if
it has a default constructor.
 Operations: Default constructor
 Models: All built-in types and STL
containers.
Basic Concepts 3
 Equality Comparable
 Concept: A type is Equality Comparable if two
values of this type can be compared for equality
using the == operator, and this operator must
define an equivalence relation.
 Operations: == and !=
 Models: All built-in numeric and pointer types.
Any STL container of the form Container<T> will
be Equality Comparable if and only if T is
Equality Comparable.
Basic Concepts 4
 Less Than Comparable
 Concept: A type is LessThan Comparable if two
values of this type can be compared using the <
operator, and this operator must define a partial
ordering. The relation, x strictly divides y, is a
partial order for integers that is not a total order.
 Operations: <, >, <=, >=
 Models: All built-in numeric types. Pointers
storing addresses within the same array.
Random Access Iterators traversing the same
container.
Basic Concepts 5
 Strict Weakly Comparable
 Concept: A type is Strict Weakly Comparable if
two values of this type can be compared using
the < operator, and this operator defines an
equivalence relation in the following sense. Two
values, x and y, are considered equivalent if both
x < y and y < x are false. Case-insensitive string
comparison is a strict weak ordering that is not a
total ordering.
Basic Concepts 6
 Refines: LessThan Comparable
 Models: All built-in numeric types. Pointers
storing addresses within the same array.
Random Access Iterators traversing the
same container.
Iterators
 An iterator is a generalization of the
concept of a pointer.
 An iterator makes it possible to traverse a
range of objects.
 Algorithms in STL generally manipulate
iterators, instead of dealing with data
structures directly.
Iterator Concept
 Trivial iterator
 Input Iterator
 Output Iterator
 Forward Iterator
 Bidirectional Iterator
 Random Access Iterator
Trivial Iterator
 Concept: An object is a Trivial Iterator if it
can be dereferenced. A Trivial Iterator may
be mutable (its dereferenced value may be
modified) or constant (the dereferenced
value cannot be modified).
 Refines: Assignable, Equality Comparable
Trivial Iterator 2
 Operations:
 Dereference: *p (p must be
dereferenceable)
 Dereference Assignment: *p = x (p must
be mutable)
 Member Access: p->m (p must be
dereferenceable)
 Equality: p == q (same as &*p == &*q)
Trivial Iterator 3
 Models: All pointer and iterator types
Input Iterator
 Concept: An object is an input iterator if it
can be dereferenced and incremented. An
input iterator must give read access to its
dereferenced value, but not necessarily
write access. Also, an input iterator does
not necessarily support a multipass
algorithm.
 Input iterators may be mutuable or
constant.
Input Iterator 2
 Refines: Trivial Iterator
 Associated Types:
 iterator_traits<X>::value_type
 The type of the object dereferenced by
iterator
 iterator_traits<X>::difference_type
 A signed integral type representing the
distance from one iterator to another.
Input Iterator 3






iterator_traits<X>::reference
Reference to the iterator’s value type.
iterator_traits<X>::pointer
Pointer to the iterator’s value type.
iterator_traits<X>::iterator_category
One of the iterator tag types: input_iterator_tag,
forward_iterator_tag, bidirectional_iterator_tag,
random_access_iterator_tag
Input Iterator 4
 Definitions:
 An iterator is past-the-end if it points
beyond the last element of a container.
 An input iterator j is reachable from input
iterator i after applying ++i a number of
times, we have i == j.
 The notation [i,j) refers to a range of
iterators beginning with I and up to but not
including j.
Input Iterator 5
 Operations:
 Those of Trivial Iterator together with:
 ++i, i++
 Note: after ++i is executed it is not
guaranteed that copies of the old value of i
be dereferenceable.
 *i++
Input Iterator 6
 Models: All pointer and STL iterators
(except for ostream_iterator). The
istream_iterator, used for traversing input
streams, is an example of an input iterator
that does not belong to any of the classes
defined below.
Output Iterator
 Concept: An object is an output iterator if
it can store to its present location and be
incremented. An output iterator must give
write access to its location, but not
necessarily read access. Also, an output
iterator does not necessarily support a
multipass algorithm.
Output Iterator 2
 Refines: Assignable
 Associated Types: Only the following
 iterator_category
 One of the iterator tag types:
output_iterator_tag, forward_iterator_tag,
bidirectional_iterator_tag,
random_access_iterator_tag
Output Iterator 3
 Operations: those of Assignable together
with
 Dereference assignment: *x = t
 ++x, x++
 Postincrement assignment: *x++ = t
Output Iterator 4
 Models: front_insert_iterator,
back_insert_iterator, insert_iterator,
ostream_iterator
Forward Iterator
 Concept: An object is a Forward Iterator if
the iterator may be incremented and gives
both read and write access (for mutable
iterators).
 Refines: Default Constructible, Input
Iterator, Output Iterator
Forward Iterator 2
 Associated Types: Same as Input
Iterator.
 Operations: Same as Default
Constructible and Input Iterator (but not
the restrictions of Input Iterator).
 Models: Pointers, all STL container
iterators
Bidirectional Iterator
 Concept: An object is a bidirectional
iterator if it allows for increments and
decrements. It gives both read and write
access (for mutable iterators).
 Refines: Forward Iterator
 Associated Types: Same as for Forward
Iterator
Bidirectional Iterator 2
 Operations: Those of Forward Iterator
together with --x, x--.
 Invariant:
 ++x; --x; or --x; ++x; are null operations
 Models: Pointers, all STL container
iterators
Random Access Iterator
 Concept: An object is a Random Access
Iterator if it allows arbitrary jumps and
pointer arithmetic.
 Refines: Bidirectional Iterator
 Associated Types: Same as for
Bidirectional Iterator.
Random Access Iterator 2
 Operations:
 i += n (equivalent to performing ++i n





times
i -= n (equivalent to i += (-n) )
i+n, n+i
Equivalent to X tmp = i; return tmp += n;
i-n;
Equivalent to X tmp = i; return tmp -= n;
Random Access Iterator 3
 More operations:
i–j
 Returns a number n such that i == j+n
 i[n]
 Equivalent to *(i + n)
 Invariants:
 If i + n is defined then i += n; i -= n; is a
null operation (similarly for i – n)
Random Access Iterator 4
 Models: Pointers and the iterators for
vector and deque containers.
Iterator Adaptors
 An iterator adaptor is a class that is a
wrapper for an iterator.
 Adaptors have their own concepts
(discussed below).
Reverse Iterator
 Concept: A reverse_iterator takes a
bidirectional or random access iterator and
creates a new iterator that traverses in the
opposite direction of usual iteration.
 Operations: *p, ++p, p++ (each performs
a decrement), --p, p--(each performs an
increment).
Reverse Iterator 2
 Example
vector<int> v;
//Suppose we place data in v
copy(v.rbegin(), v.rend(),
ostream_iterator<int>(cout," "));
 This copies the data from to cout in reverse
order. The call, v.rbegin() creates a
reverse_iterator that points to the last location in
v. The call, v.rend(), points to a position one
before the first location in v.
Istream Iterator
 Concept: An istream_iterator is used for
traversing an input stream (allowing only
read access and increments).
 Models: Input Iterator
Ostream Iterator
 Concept: An ostream_iterator is used for
traversing an output stream (allowing only
write access and decrements).
 Models: Output Iterator
Back Insert Iterator
 Concept: A back_insert_iterator takes a
container x and converts assignments into
x.push_back(). Frequently one uses the
template function back_inserter, that
returns a back_insert_iterator.
 Operations: *p, ++p, p++ (all do nothing
except return *this). *p = t (calls
x.push_back(t), where x is the container
associated with p).
Back Insert Iterator 2
 Models: Output Iterator
Front Insert Iterator
 Concept: A front_insert_iterator takes a
container x and converts assignments into
x.push_front(). Frequently one uses the
template function front_inserter, that
returns a front_insert_iterator.
 Operations: *p, ++p, p++ (all do nothing
except return *this). *p = t (calls
x.push_front(t), where x is the container
associated with p).
Front Insert Iterator 2
 Models: Output Iterator
Insert Iterator
 Concept: An insert_iterator takes a
container x and converts assignments into
x.insert(). Frequently one uses the
template function inserter, that returns a
insert_iterator.
 Operations: *p, ++p, p++ (all do nothing
except return *this). *p = t (calls
x.insert(p,t), where x is the container
associated with p).
Insert Iterator 2
 Models: Output Iterator
Example
 Suppose we want to read in a file of
grades.
multiset<int> grade_set;
ifstream in_file("grades.dat");
copy(istream_iterator<int>(in_file),
istream_iterator<int>(),
inserter(grade_set));
Iterator traits
struct input_iterator_tag {};
struct output_iterator_tag {};
struct forward_iterator_tag
: public input_iterator_tag {};
struct bidirectional_iterator_tag
: public forward_iterator_tag {};
struct random_access_iterator_tag
: public bidirectional_iterator_tag {};
Iterator traits 2
template<class Iterator>
struct iterator_traits {
typedef typename Iterator::iterator_category
iterator_category;
typedef typename Iterator::value_type
value_type;
typedef typename Iterator::difference_type
difference_type;
typedef typename Iterator::pointer
pointer;
typedef typename Iterator::reference
reference;
};
Iterator traits 3
template<class T>
struct iterator_traits<T*> {
typedef random_access_iterator_tag
iterator_category;
typedef T
value_type;
typedef ptrdiff_t
difference_type;
typedef T*
pointer;
typedef T&
reference;
};
Iterator traits 4
template<class T>
struct iterator_traits<const T*> {
typedef random_access_iterator_tag
iterator_category;
typedef T
value_type;
typedef ptrdiff_t
difference_type;
typedef const T*
pointer;
typedef const T&
reference;
};
Iterator traits 5
template<class Category, class Value,
class Distance = ptrdiff_t,
class Pointer = Value*,
class Reference = Value&>
struct iterator {
typedef Category iterator_category;
typedef Value
value_type;
typedef Distance difference_type;
typedef Pointer
pointer;
typedef Reference reference;
};
Iterator traits 6
template<class Value, class Distance,
class Pointer, class Reference>
struct BidirectionalIterator
: public Iterator<bidirectional_iterator_tag,
Value,Distance,Pointer,
Reference> {};
Iterator traits 7
template<class Value, class Distance,
class Pointer, class Reference>
struct RandomAccessIterator
: public Iterator<random_access_iterator_tag,
Value,Distance,
Pointer,Reference> {};
Iterator traits 8
template<class Value, class Distance,
class Pointer, class Reference>
struct OutputIterator
: public Iterator<output_iterator_tag,
Value,Distance,
Pointer,Reference> {};
Iterator traits 9
template<class InputIter, class Distance>
void advance(InputIter &I, Distance N)
{
Advance(I, N, typename
iterator_traits<InputIter>::iterator_category());
}
Iterator traits 10
template<class InputIter, class Distance>
void Advance(InputIter &I, Distance N,
input_iterator_tag)
{
for( ; 0 < N; --N)
++I;
}
Iterator traits 11
template<class ForwardIter, class Distance>
void Advance(ForwardIter &I, Distance N,
forward_iterator_tag) {
for( ; 0 < N; --N)
++I;
}
Iterator traits 12
template<class BidirectionalIter, class Distance>
void Advance(BidirectionalIter &I, Distance N,
bidirectional_iterator_tag) {
for( ; 0 < N; --N)
++I;
for( ; N < 0; ++N)
--I;
}
Iterator traits 13
template<class RandomAccessIter,
class Distance>
void Advance(RandomAccessIter &I,
Distance N, forward_iterator_tag) {
I += N;
}
Container concepts
 There are several container concepts that
are used in STL.
 There are three types of containers:
general containers which are models for
types of iterators, sequence containers,
and associative containers.
Container
 Concept: A Container stores other
objects. The lifetimes of these objects are
at most the lifetime of the Container.
 Refines: Assignable
 Associated Types
 X::value_type: the type of the elements of
the container. Must be Assignable.
Container 2
 X::reference: behaves as a reference to
the Container’s value type (usually just
value_type&).
 X::const_reference: usually just const
value_type&
 X::pointer: behaves as a pointer to the
Container’s elements (usually just
value_type*, but can be a smart pointer)
Container 3
 X::const_pointer: usually just const
value_type*.
 X::iterator: an iterator that points to the
Container’s elements. Must be at least an
Input Iterator.
 X::const_iterator: a constant iterator that
points to the Container’s elements.
Container 4
 X::difference_type: a signed integral type
used to measure the distance between
two of the Container’s iterators.
 X::size_type: an unsigned integral type
that can represent nonnegative values of
the Container’s difference type.
Container 5
 Operations: copy constructor,
assignment (if LHS is mutable), destructor,
begin(), end(), size(), max_size() (for that
type of Container), empty(), swap()
 Models: all STL containers.
Forward Container
 Concept: A Forward Container stores
elements in a definite order. These
containers support forward iterators.
 Refines: Container, Equality Comparable,
LessThan Comparable
 Associated Types: same as Container,
except X::iterator must be a Forward
Iterator.
Forward Container 2
 Operations: Same as Container plus the
following.
 ==, !=, <, >, <=, >= (the last four use a
lexicographical comparison).
 Models: All STL containers
Reversible Container
 Concept: A Reversible Container defines
a bidirectional iterator.
 Refines: Forward Container
 Associated Types: All types associated
with Container (with the requirement that
iterators must be Bidirectional Iterators)
plus the following:
Reversible Container 2
 X::reverse_iterator: A reverse iterator
adaptor that has X::iterator as its base
iterator type. The reverse iterator maps
operator++ to operator– (and vice versa).
 X::const_reverse_iterator: A reverse
iterator adaptor that has X::const_iterator
as its base iterator type.
Reversible Container 3
 Operations: Same as Forward Container
plus the following.
 rbegin() (points at last element of the
container)
 rend() (points at one before the first
element of the container)
 Models: All STL containers
Random Access Container
 Concept: A Random Access Container
defines a random access iterator.
 Operations: Those of Reversible
Container plus element access, a[n].
 Models: Vectors and deques.
Vector Example
 Here is a program illustrating some ways of initializing a
vector, together with a common error. The program
below inserts a range of values into vectors v1, v2, v3,
v4 by a variety of methods.
 One can insert a range of the form [first, last) via:
 - Constructor
 vector<T> v(first,last);
 - Assign member function. This method deletes any data
previously held in the vector
 v.assign(first,last)
Vector Example 2
 - Insert member function. This method does not delete
any existing data. The following inserts the range at the
end of vector. Any valid location could be used as the
insertion point.
 v.insert(v.end(), first, last);
 - Copy algorithm. This algorithm assumes that the space
for the data being copied already exists. So the following
version is incorrect if v does not already have space
allocated to hold the data to be copied. The code will
compile, but crash at run-time.
 copy(first, last, v.begin());
Vector Example 3
main()
{
int a[5] = {7, 3, 2, 5, 9};
std::vector<int> v1(&a[0], &a[5]);
std::cout << "Vector 1: ";
std::copy(v1.begin(), v1.end(), std::ostream_iterator<int>(cout," "));
cout << "\n\n";
std::vector<int> v2;
v2.assign(v1.begin(),v1.end());
cout << "Vector 2: ";
std::copy(v2.begin(), v2.end(), std::ostream_iterator<int>(cout," "));
cout << "\n\n";
Vector Example 4
vector<int> v3;
v3.insert(v3.end(),v2.begin(),v2.end());
cout << "Vector 3: ";
copy(v3.begin(), v3.end(), ostream_iterator<int>(cout," "));
cout << "\n\n";
vector<int> v4;
//copy(v3.begin(), v3.end(), v4.begin());
copy(v3.begin(), v3.end(), back_inserter(v4));
cout << "Vector 4: ";
copy(v4.begin(), v4.end(), ostream_iterator<int>(cout," "));
cout << "\n\n";
}
Sequence Container
 Concept: A Sequence stores its elements
in a linear ordering.
 Refines: Forward Container, Default
Constructible
 Operations: Those of Forward Container
plus,
 Default constructor,
Sequence Container 2
 Fill constructor c(n,x) creates container
with n copies equal to x
 Fill constructor c(n) creates container with
n elements initialized to default value,
 Range constructor c(i,j). Here, i and j are
input iterators. Creates a sequence that is
a copy of the range [i,j).
Sequence Container 3
 Insert: c.insert(p,x) inserts the value x




before position p.
Special cases:
a.insert(a.begin(), x) inserts x before the
first element of a.
a.insert(a.end(),x) inserts x after the last
element of a.
Note: the iterator p need not be valid after
the insert is performed.
Sequence Container 4
 Fill insert: a.insert(p, n, x) inserts n copies
of value x before position p.
 This is guaranteed to be no slower than
calling insert(p,x) n times.
 Range insert: a.insert(p, i, j) inserts a copy
of the range [i,j) before position p.
Sequence Container 5
 Erase: a.erase(p) erases the element at
position p.
 This assumes that p is dereferenceable.
 It returns an iterator to the element
immediately following the one removed or
else a.end() if there is no such element.
 Note: erase may invalidate iterators into
the sequence.
Sequence Container 6
 Range erase: a.erase(p,q) erases all
elements in the range [p,q).
 The return value is an iterator pointing to
the element immediately after the range
that was removed or a.end() if no such
element exists.
Sequence Container 7
 Front: a.front() returns a reference to the
first element in the sequence.
 Assumes the sequence is not empty.
 Models: vector, list, deque
Sequence Container 8
 Can the range insertion be used to copy
from a container to itself?
 Can the range overlap with the position of
the insertion?
 Consider the following example.
Sequence Container 9
main() {
std::vector<int> v;
int a[ ] = {5,2,3,4,6};
v.insert(v.end(),&a[0],&a[5]);
std::vector<int>::iterator p,i;
p = find(v.begin(),v.end(),2);
v.insert(p,v.begin(),v.end());
copy(v.begin(),v.end(),
std::ostream_iterator<int>(std::cout, " "));
std::cout << '\n';
}
Sequence Container 10
 The output is
5523462346
 How does the insert function work?
vector::insert
template<class InputIter>
void insert(iterator p, InputIter F, InputIter L)
{
size_type M = F - L;
size_type N = capacity();
vector::insert 2
if (M == 0)
;
else if (max_size() < M + size())
throw length_error("vector too long");
vector::insert 3
else if (N < size() + M) {
N = (max_size() < N + N/2) ? N + N/2 : size() + M;
pointer S = Mybase::Alval.allocate(N, (void *) 0);
pointer Q;
Q = copy(begin(),P,S);
Q = copy(F,L,Q);
copy(P,end(),Q);
}
vector::insert 4
else if ( (size_type) (end() - P) < M ) {
copy(P, end(), P+M);
InputIter Mid = F;
advance(Mid, end() - P);
copy(Mid, L, end());
copy(F, Mid, P);
}
vector::insert 5
else if ( 0 < M ) {
iterator Old_end() = end();
copy(Old_end - M, Old_end, end());
copy_backward(P, Old_end - M, Old_end);
copy(F,L,P);
}
}
GCC vector::insert
template<typename _Tp, typename _Alloc>
template<typename _ForwardIterator>
void
vector<_Tp,_Alloc>::
_M_range_insert(iterator __position,_ForwardIterator
__first, _ForwardIterator __last, forward_iterator_tag)
{
GCC vector::insert 2
if (__first != __last)
{
size_type __n = std::distance(__first, __last);
if (size_type(this->_M_impl._M_end_of_storage –
this->_M_impl._M_finish) >= __n)
{
GCC vector::insert 3
const size_type __elems_after = end() - __position;
iterator __old_finish(this->_M_impl._M_finish);
if (__elems_after > __n)
{
std::uninitialized_copy(this->_M_impl._M_finish __n, this->_M_impl._M_finish, this->_M_impl._M_finish);
this->_M_impl._M_finish += __n;
std::copy_backward(__position, __old_finish - __n,
__old_finish);
std::copy(__first, __last, __position);
}
GCC vector::insert 4
else
{
_ForwardIterator __mid = __first;
std::advance(__mid, __elems_after);
std::uninitialized_copy(__mid, __last,
this->_M_impl._M_finish);
this->_M_impl._M_finish += __elems_after;
std::copy(__first, __mid, __position);
}
}
GCC vector::insert 5
else
{
const size_type __old_size = size();
const size_type __len = __old_size +
std::max(__old_size, __n);
iterator __new_start(this->_M_allocate(__len));
iterator __new_finish(__new_start);
try
{
__new_finish =
std::uninitialized_copy(iterator(this->_M_impl._M_start),
__position, __new_start);
GCC vector::insert 6
__new_finish =
std::uninitialized_copy(__first, __last, __new_finish);
__new_finish = std::uninitialized_copy(__position,
iterator(this->_M_impl._M_finish), __new_finish);
}
catch(...)
{
std::_Destroy(__new_start,__new_finish);
_M_deallocate(__new_start.base(), __len);
__throw_exception_again;
}
GCC vector::insert 7
std::_Destroy(this->_M_impl._M_start,
this->_M_impl._M_finish);
_M_deallocate(this->_M_impl._M_start,
this->_M_impl._M_end_of_storage –
this->_M_impl._M_start);
this->_M_impl._M_start = __new_start.base();
this->_M_impl._M_finish = __new_finish.base();
this->_M_impl._M_end_of_storage =
__new_start.base() + __len;
}
}
}
Is this legal?
template<class T>
class my_sequence {
private:
//Some data
public:
//Assume the appropriate iterator has been defined
//Consider the following insert functions
void insert(iterator p, size_type n, const T &t)
{ std::cout << "insert(p,n,t)\n"; }
template<class InputIterator>
void insert(iterator p, InputIterator first, InputIterator last)
{ std::cout << "insert(p,first,last)\n"; }
};
Example 2
main() {
my_sequence<int> m;
m.insert(m.begin(), 100, 5);
return 0;
}
This is legal. But not what one might expect.
The output is:
insert(p,first,last)
In other words, the compiler decides that
m.insert(m.begin(), 100, 5);
best fits the second insert function (whereas we
expected to match the first).
Why is that?
void insert(iterator p, InputIterator first, InputIterator last)
Is an exact match because the last two
arguments for m.insert(m.begin(), 100, 5) are
both ints.
So the compiler matches the type InputIterator to
int.
But in the other insert function,
void insert(iterator p, size_type n, const T &t)
The compiler matches T to be an int. Usually
size_t will be a typedef for unsigned int. So that
m.insert(m.begin(), 100, 5) is not an exact
match for this version of insert.
Where did we go wrong?
 This is actually a very difficult problem to
solve. There is no simple way to get the
compiler to match the correct version of
insert.
 One could specialize the class for the case
when T is an int.
 One could overload the first insert function
for cases where the second argument is
an int, a long, etc.
Where did we go wrong? 2
 These methods are cumbersome (one has
to write a lot of extra code that looks
exactly the same).
 Another solution is to test if the parameter
type InputIter is an integral type. There is a
static member of the class numeric_limits
called is_integer.
Where did we go wrong? 3
 How does that work? The class
numeric_limits looks like:
template<class T>
class numeric_limits {
public:
static const bool is_integer = false;
//…
};
Where did we go wrong? 4
 There are specialized versions of
numeric_limits for each integral type.
 In each of these specialized classes
is_integer is set equal to true.
Corrected version
#include<iostream>
#include<limits>
template<bool B>
struct int_test { };
template<class T>
class my_sequence {
public:
typedef T* iterator;
private:
//Some data
Corrected version 2
private:
void fill_insert(iterator p, unsigned int n,
const T &t)
{ std::cout << "insert(p,n,t)\n"; }
template<class InputIter>
void range_insert(iterator p, InputIter first,
InputIter last)
{ std::cout << "insert(p,first,last)\n"; }
Corrected version 3
template<class Integral>
void insert(iterator p, Integral n, Integral t,
int_test<true>) {
fill_insert(p,n,t);
}
template<class InputIter>
void insert(iterator p, InputIter f, InputIter l,
int_test<false>) {
range_insert(p,f,l);
}
Corrected version 4
public:
//Consider the following insert functions
void insert(iterator p, unsigned int n, const T &t) {
fill_insert(p,n,t);
}
template<class InputIter>
void insert(iterator p, InputIter first, InputIter last)
{
insert(p,first,last,
int_test<std::numeric_limits<InputIter>::is_integer>());
}
};
Corrected version 5
main() {
my_sequence<int> m;
m.insert(m.begin(), 100, 5);
return 0;
}
//Output is now
insert(p,n,t)
Front Insertion Sequence
 Concept: A container is a Front Insertion
Sequence if it allows insertion/deletion of
an element at the beginning of a sequence
in constant time.
 Refines: Sequence
 Operations: In addition to the Sequence
operations we have the following:
Front Insertion Sequence 2
 Push front: a.push_front(t) is equivalent to
a.insert(a.begin(),t)
 Pop front: a.pop_front() is equivalent to
a.erase(a.begin(),t). Has a void return.
 Note: push_front followed by
pop_front is a null operation.
Back Insertion Sequence
 Concept: A container is a Back Insertion
Sequence if it allows insertion/deletion of
an element at the end of a sequence in
constant time.
 Refines: Sequence
 Operations: In addition to the Sequence
operations we have the following:
Back Insertion Sequence 2
 Back: a.back() returns a reference or
const_reference to the final element of a
(depending on whether the container a is
const).
 Push back: a.push_back(t) is equivalent to
a.insert(a.end(), t)
 Pop back: a.pop_back() is equivalent to
a.erase(--a.end()). Has a void return.
Associative Container
 Concept: An Associative Container accesses
elements in the container based on keys. Keys
are kept in a sorted order (where the user may
supply the sorting criterion). The keys and
associated values are stored with a tree data
structure (in particular, a red-black tree is the
usual implementation). Since the sorted order of
the keys is an invariant for this container,
insertions are not allowed to specify the position
of insertion.
Associative Container 2
 Refines: Forward Container, Default
Constructible
 Associated Types: those of Forward
Container together with,
 X::key_type the type of the key associated
with X::value_type
Associative Container 3
 Operations: Same as Forward Container
together with the following
 Default Constructor
 Find: a.find(k) returns an iterator pointing
to an element whose key is k. Returns
a.end() if key not found.
 Count: a.count(k) returns the number of
elements whose key is k.
Associative Container 4
 Equal Range: a.equal_range(k) returns a
pair P of iterators with key equal to k. The
range is [P.first,P.second).
 Erase key: a.erase_key(k) erase all
elements whose key is k.
 Erase element: a.erase(p) erases the
element pointed to by p.
 Erase range: a.erase(i,j) erases the
elements in the range [i,j)
Associative Container 5
 Models: set, multiset, map, multimap
Associative Container FAQ
 What does end() return for an associative
container?
 end() returns an iterator to a special tree
node Head.
 This node contains no data, its left pointer
points at the smallest element in the tree,
its right pointer points at the largest
element in the tree, its parent is the root.
Associative Container FAQ 2
 How do you increment an iterator for an
Associative Container?
 Such iterators internally store a node
pointer Ptr.
void increment()
{
if ( Isnil(Ptr) )
;
else if ( !Isnil(Right(Ptr)) )
Ptr = Min(Right(Ptr));
else {
Nodeptr P;
while ( !Isnil(P = Parent(Ptr))
&& Ptr == Right(P) )
Ptr = P;
Ptr = P;
}
}
Associative Container FAQ 3
 How do lower_bound(), upper_bound()
and equal_range() work?
 Lower_bound finds the first of an
equivalent sequence of keys.
 Upper_bound finds the first element past
an equivalent sequence of keys.
 Equal_range returns the pair of iterators,
lower_bound and upper_bound.
Nodeptr Lbound(const key_type &k) const
{
Nodeptr X = Root();
Nodeptr Y = Head;
while( !Isnil(X) )
if( comp(Key(X),k) )
X = Right(X);
else {
Y = X;
X = Left(X);
}
return Y;
}
Nodeptr Ubound(const key_type &k) const
{
Nodeptr X = Root();
Nodeptr Y = Head;
while( !Isnil(X) )
if( comp(k,Key(X)) ) {
Y = X;
X = Left(X);
}
else
X = Right(X);
return Y;
}
Unique Associative Container
 Concept: A Unique Associative Container
is an Associative Container with the
property that each key in the container is
unique. An element doesn’t get inserted
into a container if its key is already
present.
 Refines: Associative Container
Unique Associative Container 2
 Operations: Same as Associative
Container plus,
 Range constructor: X a(i,j) creates an
associative container that includes all
elements in [i,j) that have unique keys.
Unique Associative Container 3
 Insert element: a.insert(t) inserts the
element if and only if t’s key is not already
in container. Returns pair<iterator,bool>. If
element is already in container, iterator
points to an element in the container with
that key and the bool is false. If the
element not in the container then the
iterator points to where the element is
inserted and the bool is true.
Unique Associative Container 4
 Insert range: a.insert(i,j) inserts all the
elements in [i,j) whose key is not already
in the container.
 Models: set, map
Multiple Associative Container
 Concept: A Multiple Associative Container
is an Associative Container that may
contain more than one element with the
same key.
 Refines: Associative Container
 Operations: Those of Associative
Container together with the following,
Multiple Associative Container 2
 Range constructor: X a(i,j) creates an
associative container that contains all the
elements in the range [i,j).
 Insert element: a.insert(t) inserts t and
returns a pointer to the newly inserted
element.
 Insert range: a.insert(i,j) inserts all the
elements in the range [i,j).
Multiple Associative Container 3
 Models: multiset, multimap
Simple Associative Container
 Concept: A Simple Associative Container
is an Associative Container whose
elements are their own keys. A value
stored in such a container is just a key, not
a key plus additional data.
 Refines: Associative Container
Simple Associative Container 2
 Associated Types: Those of Associative
Container together with:
 X::iterator. Mutable iterators are not
allowed for Simple Associative Containers.
Both X::iterator and X::const_iterator must
have the same behavior.
 Invariant: Elements are immutable. They
cannot be modified in place (but can be
removed).
Simple Associative Container 3
 Models: set and multiset.
Pair Associative Container
 Concept: A Pair Associative Container




associates a key with some other object.
Refines: Associative Container
Associated Types: Those of Associative
Container together with
X::key_type the type of an element’s key.
X::mapped_type the type of an element’s
data. The container associates keys and
values of type mapped_type.
Pair Associative Container 2
 X::value_type the type of object stored in
the container. The value type is
pair<const key_type, mapped_type>. Note
the use of const key_type. This happens
because the keys in a Pair Associative
Container are immutable. The
mapped_type part of an element may be
modified but not the key.
Pair Associative Container 3
 X::iterator. A Pair Associative Container
cannot provide mutable iterators. This is
because the value type of a mutable
iterator must be Assignable and
pair<const key_type, mapped_type> is not
Assignable. However iterators are not
constant since you are allowed to have
expressions such as i->second = val.
Pair Associative Container 4
 Models: map and multimap
Sorted Associative Container
 Concept: A Sorted Associative Container
sorts elements by key, using a Strict Weak
Ordering.
 Refines: Associative Container and
Reversible Container.
 Associated Types: Those of Associative
and Reversible Container together with the
following:
Sorted Associative Container 2
 X::key_compare is a function object type.
It uses a Strict Weak Ordering to compare
keys. It takes two arguments of type
X::key_type and returns a bool.
 X::value_compare is a function object that
compares two objects of value_type by
passing the keys associated with these
objects to a function object of type
key_compare.
Sorted Associative Container 3
 Operations: Those of Associative
Container and Reversible Container
together with:
 Default constructor: X() creates an empty
container using key_compare() as the
comparison function.
 Default constructor with comparison: X(c)
creates an empty container with
comparison function c.
Sorted Associative Container 4
 Range constructor: X(i,j) is equivalent to
X a;
a.insert(i,j);
 Range constructor with comparison:
X(i,j,c) is equivalent to
X a(c);
a.insert(i,j);
Sorted Associative Container 5
 Key comparison: a.key_comp() returns a’s
key comparison object.
 Value comparison: a.value_comp() returns
a’s value comparison object.
 Lower bound: a.lower_bound(k) returns
an iterator to the first element whose key
is not less than k. It returns a.end() if no
such element is present.
Sorted Associative Container 6
 Upper bound: a.upper_bound(k) returns
an iterator to the first element whose key
is greater than k. It returns a.end() if no
such element exists.
Sorted Associative Container 7
 Equal range: a.equal_range(k) returns a
pair P such that P.first is a.lower_bound(k)
and P.second is a.upper_bound(k). If there
are no elements equal to k then an empty
range is returned that indicates the
position where those elements would have
been if they did exist. All elements with key
k will be contained in the range [P.first,
P.second).
Equal range example
#include <iostream>
#include <set>
#include <algorithm>
#include <iterator>
#include <utility>
main() {
std::multiset<int> s;
s.insert(5);
s.insert(3);
s.insert(12);
s.insert(6);
s.insert(6);
s.insert(10);
Equal range example 2
std::copy(s.begin(), s.end(),
std::ostream_iterator<int>(std::cout, " "));
std::cout << '\n';
typedef std::multiset<int>::const_iterator CI;
Equal range example 3
std::pair<CI,CI> pi = s.equal_range(6);
std::copy(pi.first, pi.second,
std::ostream_iterator<int>(std::cout, " "));
std::cout << '\n';
Equal range example 4
pi = s.equal_range(11);
if (pi.first == s.end())
std::cout << "equal_range returned end()\n";
if (pi.second == s.end())
std::cout << "equal_range returned end()\n";
std::cout << "equal_range.first = "
<< *pi.first << '\n';
std::cout << "equal_range.second = "
<< *pi.second << '\n';
Equal range example 5
std::copy(pi.first, pi.second,
std::ostream_iterator<int>(std::cout, " "));
std::cout << '\n';
return 0;
}
Equal range example 6
 Output
3 5 6 6 10 12
66
equal_range.first = 12
equal_range.second = 12
Example
 Here is a small music database. We will
load the database and then do a simple
query, “Print out all songs sung by Billie
Holiday in the database.”
Artist
Billie Holiday
Billie Holiday
Billie Holiday
Bix Beiderbecke
Bix Beiderbecke
Ruth Etting
Bunny Berigan
Louis Armstrong
Louis Armstrong
Jack Jenney
Song
Mean to Me
Summertime
I Can’t Get Started
In a Mist
Singin’ the Blues
Singin’ the Blues
I Can’t Get Started
Chinatown
Stardust
Stardust
#include<iostream>
#include <map>
#include <string>
using namespace std;
typedef string artist;
typedef string song;
typedef multimap<artist,song>::iterator
music_iterator;
main()
{
multimap<artist,song> music;
music.insert(make_pair("Billie Holiday",
"Mean to Me"));
music.insert(make_pair("Billie Holiday",
"Summertime"));
music.insert(make_pair("Billie Holiday",
"I Can\'t Get Started"));
music.insert(make_pair("Bix Beiderbecke",
"Singin\' the Blues"));
music.insert(make_pair("Bix Beiderbecke",
"In a Mist"));
music.insert(make_pair("Ruth Etting",
"Singin\' the Blues"));
music.insert(make_pair("Bunny Berigan",
"I Can\'t Get Started"));
music.insert(make_pair("Louis Armstrong",
"West End Blues"));
music.insert(make_pair("Louis Armstrong",
"Stardust"));
music.insert(make_pair("Louis Armstrong",
"Chinatown"));
music.insert(make_pair("Jack Jenney", "Stardust"));
music.insert(make_pair("Sidney Bechet",
"Summertime"));
music.insert(make_pair("Sidney Bechet",
"Wild Man Blues"));
music.insert(make_pair("Cootie Williams",
"West End Blues"));
//Find songs by Billie Holiday
pair<music_iterator,music_iterator> p =
music.equal_range("Billie Holiday");
//Print out songs by Billie Holiday
cout << "Songs by Billie Holiday\n";
for(music_iterator i = p.first, i != p.second; i++)
cout << i->second << '\n';
return 0;
}
OUTPUT
Songs by Billie Holiday
Mean to Me
Summertime
I Can't Get Started
Allocator
 Concept: Manages the details of memory
allocation and deallocation.
 Refines: Equality Comparable and Default
Constructible.
 Associated Types:
 X::value_type the type that the allocator
manages
Allocator 2
 X::pointer is a pointer (not necessarily a
built-in pointer type) to X::value_type. The
pointer type must be convertible to
const_pointer, void*, and value_type*.
 X::const_pointer is a const pointer to
X::value_type.
 X::reference is a reference to
X::value_type (must be X::value_type&).
Allocator 3
 X::const_reference is a const reference to
X::value_type (must be const
X::value_type&).
 X::difference_type is a signed integral type
that represents the difference of two
values of type X::pointer.
 X::size_type is an unsigned integral type
that can represent any non-negative value
of type X::difference_type.
Allocator 4
 X::rebind<U>::other is an allocator whose
type is U.
 Operations:
 Default constructor: X() creates a default
allocator.
 Copy constructor: X b(a) creates a copy of
a (and compares equal to a).
Allocator 5
 Generalized copy constructor: X a(y)
creates a copy of y, an Allocator of value
type U.
 Comparison: a == b returns true if and
only if the storage allocated by a can be
deallocated using b and vice versa.
 Allocate: a.allocate(n) allocates n*sizeof(T)
bytes and returns a pointer to an
uninitialized block of memory.
Allocator 6
 Allocate with hint: a.allocate(n,p) allocates
n*sizeof(T) bytes. The pointer p is a hint to
where the memory may be allocated (the
hint may be simply ignored). Returns a
pointer to an uninitialized block of memory.
 Deallocate: a.deallocate(p, n) frees the
memory for n objects of type T stored at
location p. The pointer p must have been
obtained from a previous call to allocate.
Allocator 7
 Maximum size: a.max_size returns the
maximum number of elements that may be
passed as the first argument to allocate.
 Construct: a.construct(p, val) constructs
an object of type T at position p.
Equivalent to the placement new operator
new( (void *) p) T(val).
Allocator 8
 Destroy: a.destroy(p) destroys the object
pointed to by p. Equivalent to
( (T*) p) -> ~T()
 Address: a.address(t) returns of object t (in
the form of a pointer or const pointer)
Container Adaptors
 A container adaptor is a class that provide
a limited number of container operations.
 There are three container adaptors in STL:
stack, queue, and priority queue.
 These classes are implemented in terms
of underlying containers.
Stack
 Concept: A stack adapts a sequence container
(deque by default). It permits insertion, deletion,
or inspection only at one end of the sequence
(designated the top of the stack). Stacks do not
have iterators.
 Template parameters: stack<T,C>. Here T is
the type of element stored in stack and C is the
underlying sequence container.
Stack 2
 Members
 stack::value_type is the type of object
stored in the stack.
 Default constructor: stack::stack() declares
an empty stack.
 Constructor with sequence: stack::stack(c)
declares a stack having the same
elements as container c.
Stack 3
 Copy constructor, destructor, assignment
operator, size(), empty()
 top() returns a mutable reference to the
top of the stack. It actually returns
c.back().
 push(x) inserts x at the top of the stack.
Calls c.push_back(x).
Stack 4
 pop() removes (but does not return) the
element at the top of the stack. Calls
c.pop_back().
 Type Requirements: Container C is a
model of Back Insertion Sequence.
Queue
 Concept: A queue adapts a sequence
container (deque by default). A queue is a
model of a “first in first out” container.
Elements are inserted at the back and
removed from the front of the sequence.
Iterators are not allowed on queues.
 Template parameters: queue<T,C>. Here T
is the type of element stored in stack and C is
the underlying sequence container.
Queue 2
 Members:
 queue::value_type is the type of object
stored in the queue.
 Default constructor: queue::queue()
declares an empty queue.
 Constructor with sequence: queue::
queue(c) declares a queue having the
same elements as container c.
Queue 3
 Copy constructor, destructor, assignment
operator, size(), empty()
 front() returns the element at the front of
the queue. Calls c.front().
 back() returns the element at the back of
the queue. Calls c.back().
 push(x) inserts x at the back of the queue.
No value is returned. Calls
c.push_back(x).
Queue 4
 pop() removes the element at the front of
the queue.
 Type Requirements: Container C is a
model for Back Insertion Sequence and
Front Insertion Sequence.
Priority Queue
 Concept: A priority queue adapts a
sequence container (vector by default). It
provides for insertion of elements, and
inspection and removal of the top element.
Iterators and the modification of elements
are not permitted. The top element is
always the largest in the queue (elements
are ordered using < by default). The
elements are stored in a heap.
Priority Queue 2
 Template Parameters:
priority_queue<T,C,Compare>. T is the
type of element stored in queue. C is the
underlying sequence container. Compare
is the comparison function used to find the
largest element in the queue.
Priority Queue 3
 Members:
 priority_queue::value_type is the same as
T.
 Default constructor creates a priority
queue with the default container and
compare function.
 Constructor with compare function: explicit
priority_queue::priority_queue(Compare
comp).
Priority Queue 4
 Constructor with comparison and
sequence:
priority_queue::priority_queue(Compare
comp, C cont).
 Range constructor with comparison, range
constructor with comparison and
container.
Priority Queue 5
 Destructor, assignment operator, size(),
empty().
 top() returns a const reference to the
largest element of the queue (which would
be the root of the heap). Calls c.front().
 push(x) inserts x into the queue. Calls
c.push_back() and then “bubbles up” the
heap.
Priority Queue 6
 pop() removes the element at the top of
the queue. Switches the top and bottom
elements of the heap, rebuilds the hea,
and then calls c.pop_back().
 Type Requirements: Container must be a
Random Access Container. Compare must
be a Strict Weak Ordering.
Functors
 A functor, or function object, is any object that
can be used using function call syntax.
 A function pointer is a functor, as is any object of
a class that overloads the function call operator,
i.e., operator().
 A pointer to a member function is not a functor.
 The standard library functors are limited to
generators, unary and binary functions, but still
provide a useful starting point for someone
writing their own functors.
Functors 2
 A unary function returning a bool is called
a Predicate. A binary function returning a
bool is called a Binary Predicate.
 An adaptable functor has typedefs for its
argument types and return type.
 Adaptable functors can be used by
function adaptors.
Generator
 Concept: A Generator is a function object




called with no arguments.
Refines: Assignable
Associated Types: Result type, the type
returned when the Generator is called.
Operations: function call f().
Models: any function R (*)().
Unary Function
 Concept: A Unary Function is a function
object that is called with a single
argument.
 Refines: Assignable
 Associated Types:
 Argument type: Argument type is the type
of the function’s argument.
Unary Function 2
 Result type: result_type is the type of the
return value.
 Operation: function call f(x)
 Models: any function R (*)(T)
Binary Function
 Concept: A Binary Function is a function
object that is called with two arguments.
 Refines: Assignable
 Associated Types:
 Argument types: First argument type and
Second argument type are the types of the
function’s arguments.
Binary Function 2
 Result type: Result type is the type of the
return value.
 Operation: function call f(x,y)
 Models: any function R (*)(T1,T2)
Adaptive Generator
 Concept: An Adaptive Generator is a




Generator that has a nested typedef for
the return type.
Refines: Assignable
Associated Types: f::result_type, the type
returned when the Generator is called.
Operations: function call f().
Models: None in standard library
Adaptive Unary Function
 Concept: An Adaptive Unary Function is a
Unary Function that has nested typedefs
for the argument and return types.
 Refines: Assignable
 Associated Types:
 Argument type: f::argument_type is the
type of the function’s argument.
Adaptive Unary Function 2
 Result type: f::result_type is the type of the
return value.
 Operation: function call f(x)
 Models: negate, logical_not,
pointer_to_unary_function.
Adaptive Binary Function
 Concept: An Adaptive Binary Function is a
Binary Function with nested typedefs for
the argument and return types.
 Refines: Assignable
 Associated Types:
 Argument types: f::first_argument_type
and f::second_argument_type are the
types of the function’s arguments.
Adaptive Binary Function 2
 Result type: result_type is the type of the
return value.
 Operation: function call f(x,y)
 Models: plus, minus, multiplies, divides,
modulus, equal_to, not_equal_to, greater,
less, greater_equal, less_equal,
logical_and, logical_or,
pointer_to_binary_function.
Predicate
 Concept: A Predicate is a Unary Function
whose return is a bool.
 Refines: Unary Function
 Associated Type: the Result type must
be convertible to bool.
 Models: Any function of the form
bool (*)(T)
Binary Predicate
 Concept: A Binary Predicate is a Binary
Function that returns a bool.
 Refines: Binary Function
 Associated Types: the Result type must
be a bool.
 Models: Any function of the form
bool
(*)(T1,T2)
Adaptive Predicate
 Concept: An Adaptive Predicate is a
Predicate with nested typedefs for the
argument and return types.
 Refines: Predicate, Adaptive Unary
Function
 Models: logical_not
Adaptive Binary Predicate
 Concept: An Adaptive Binary Predicate is
a Binary Predicate with nested typedefs
for the argument and return types.
 Refines: Binary Predicate, Adaptive Unary
Function
 Models: equal_to, not_equal_to, greater,
less, greater_equal, less_equal,
logical_and, logical_or
Example
 Here is an example of a user defined adaptive binary
predicate. This functor returns true if string s1 contains
string s2 as a substring.
class str_contains : public
binary_function<string,string,bool>{
public:
bool operator() (const string &s1, const string &s2)
{
return s1.find(s2) != string::npos;
}
};
RNG Example
 Here is an adaptive unary functor that was
almost part of STL.
 This is an example of a subtractive
random number generator.
RNG Example 2
class subtractive_rng : public
std::unary_function<unsigned int, unsigned int> {
private:
unsigned int _M_table[55];
size_t _M_index1;
size_t _M_index2;
public:
// Returns a number less than the argument.
unsigned int operator()(unsigned int __limit) {
_M_index1 = (_M_index1 + 1) % 55;
_M_index2 = (_M_index2 + 1) % 55;
_M_table[_M_index1] = _M_table[_M_index1] _M_table[_M_index2];
return _M_table[_M_index1] % __limit;
}
RNG Example 3
void _M_initialize(unsigned int __seed)
{
unsigned int __k = 1;
_M_table[54] = __seed;
size_t __i;
for (__i = 0; __i < 54; __i++) {
size_t __ii = (21 * (__i + 1) % 55) - 1;
_M_table[__ii] = __k;
__k = __seed - __k;
__seed = _M_table[__ii];
}
for (int __loop = 0; __loop < 4; __loop++) {
for (__i = 0; __i < 55; __i++)
_M_table[__i] = _M_table[__i] - _M_table[(1 + __i + 30) % 55];
}
_M_index1 = 0;
_M_index2 = 31;
}
RNG Example 4
// Ctor allowing you to initialize the seed.
subtractive_rng(unsigned int __seed) { _M_initialize(__seed); }
// Default ctor; initializes its state with some number you don't
see.
subtractive_rng() { _M_initialize(161803398u); }
};
main()
{
subtractive_rng s;
for(int i = 0; i < 20; i++)
std::cout << s(10) << ' ';
std::cout << '\n';
}
RNG Example 5
 Here is the output from the above
program.
32167078093217693106
Function adaptors
 A function adaptor converts one type of
function object into another type.
 For example, the functions bind1st and
bind2nd convert an Adaptable Binary
Function into an Adaptable Unary
Function.
Class binder1st
 Takes an Adaptable Binary Function F(x,y)
and converts it into an Adaptable Unary
Function f(y) = F(c,y) where c is a
constant.
 The function bind1st returns a binder1st
object.
 For example, bind1st(equal_to<int>(),10)
returns a function object which acts like
equal_to(10,y).
Class binder1st 2
template <class _Operation>
class binder1st
: public unary_function<
typename _Operation::second_argument_type,
typename _Operation::result_type>
{
protected:
_Operation op;
typename _Operation::first_argument_type value;
Class binder1st 3
public:
binder1st(const _Operation& __x,
const typename _Operation::first_argument_type& __y)
: op(__x), value(__y) { }
typename _Operation::result_type
operator()
(const typename
_Operation::second_argument_type& __x) const
{ return op(value, __x); }
};
Class binder1st 4
template <class _Operation, class _Tp>
inline binder1st<_Operation>
bind1st(const _Operation& __fn,
const _Tp& __x)
{
typedef typename _Operation::first_argument_type
_Arg1_type;
return binder1st<_Operation>(__fn, _Arg1_type(__x));
}
Class binder2nd
 Takes an Adaptable Binary Function F(x,y)
and converts it into an Adaptable Unary
Function f(x) = F(x,c) where c is a
constant.
 The function bind2nd returns a binder2nd
object.
 For example, bind2nd(equal_to<int>(),10)
returns a function object which acts like
equal_to(x,10).
Binder example
 We have a list of student grades. We want to
copy the grades which are below 60 into a
failures list. Since STL does not provide a
copy_if function we use the next best thing, the
remove_copy_if function.
 This function copies all elements from a source
range for which a given predicate evaluates as
false (i.e., it 'removes' the ones which make
the predicate true).
Binder example 2
 So we will remove_copy_if() all grades
which are greater than or equal to 60.
There is a built-in greater_equal binary
predicate. We will bind its second
argument to 60, to turn it into the unary
predicate that we want to use.
Binder example 3
main()
{
int a[10] = { 50, 80, 60, 40, 30, 90, 100, 20 ,40 ,70 };
vector<int> grades(&a[0], &a[10]);
vector<int> failures;
remove_copy_if(grades.begin(), grades.end(),
back_inserter(failures),
bind2nd(greater_equal<int>(),60));
cout << "Failing grades\n";
copy(failures.begin(), failures.end(), ostream<int>(cout, “ "));
return 0;
}
Binder example 4
 Output
Failing grades
50 40 30 20 40
Class pointer_to_unary_function
 Takes a pointer to a unary function and
converts it into an Adaptable Unary
Function.
 The function ptr_fun returns a
pointer_to_unary_function object.
pointer_to_unary_function 2
template <class _Arg, class _Result>
class pointer_to_unary_function :
public unary_function<_Arg, _Result>
{
protected:
_Result (*_M_ptr)(_Arg);
public:
pointer_to_unary_function() { }
pointer_to_unary_function 3
explicit pointer_to_unary_function(_Result
(*__x)(_Arg)) : _M_ptr(__x) { }
_Result operator() (_Arg __x) const
{ return _M_ptr(__x); }
};
pointer_to_unary_function 4
template <class _Arg, class _Result>
inline pointer_to_unary_function<_Arg, _Result>
ptr_fun(_Result (*__x)(_Arg)) {
return
pointer_to_unary_function<_Arg, _Result>(__x);
}
Example
 Suppose we want to transform the
elements of a vector into the negative of
their absolute value.
Example 2
vector<int> v;
//…
transform(v.begin(), v.end(), v.begin(),
compose1(negate<int>(),
ptr_fun(fabs)));
Example 3
 Here compose1 is a function returning the
function adaptor, unary_compose.
 The function unary_compose takes two
functions f, g and returns their composition
h defined by h(x) = f(g(x)).
 These elements, compose1 and
unary_compose are not in the C++
standard.
Example 4
template <class OP1, class OP2>
class unary_compose: public
std::unary_function<typename OP2::argument_type,
typename OP1::result_type>
{
private:
OP1 op1; // process: op1(op2(x))
OP2 op2;
Example 5
public:
// constructor
unary_compose(const OP1& o1, const OP2& o2)
: op1(o1), op2(o2) {
}
// function call
typename OP1::result_type
operator()(const typename OP2::argument_type& x)
const
{
return op1(op2(x)); }
};
Example 6
template <class OP1, class OP2>
inline unary_compose<OP1,OP2>
compose1(const OP1& o1, const OP2& o2
{
return unary_compose<OP1,OP2>(o1,o2);
}
Class pointer_to_binary_function
 Takes a pointer to a binary function and
converts it into an Adaptable Binary
Function.
 The function ptr_fun returns a
pointer_to_binary_function object.
Class pointer_to_binary_function 2
template <class _Arg1, class _Arg2, class
_Result>
class pointer_to_binary_function
: public binary_function<_Arg1, _Arg2, _Result>
{
protected:
_Result (*_M_ptr)(_Arg1, _Arg2);
public:
pointer_to_binary_function() { }
Class pointer_to_binary_function 3
explicit
pointer_to_binary_function(
_Result (*__x)(_Arg1, _Arg2))
: _M_ptr(__x) { }
_Result
operator()(_Arg1 __x, _Arg2 __y) const
{ return _M_ptr(__x, __y); }
};
Class pointer_to_binary_function 4
template <class _Arg1, class _Arg2, class _Result>
inline pointer_to_binary_function<_Arg1, _Arg2,
_Result>
ptr_fun(_Result (*__x)(_Arg1, _Arg2))
{
return
pointer_to_binary_function<_Arg1, _Arg2,
_Result>(__x);
}
Example
list<char *> L;
list<char *>::iterator li =
find_if(L.begin(), L.end(),
not1(binder2nd(ptr_fun(strcmp), “OK”)));
Class unary_negate
 Class unary_negate is an Adaptable
Predicate that represents logical negation
of some other Adaptable Predicate.
 If f is a unary_negate object constructed
with predicate pred, then f(x) returns
!pred(x).
 The function not1 returns a unary_negate
object.
Class binary_negate
 Class binary_negate is an Adaptable
Binary Predicate that represents logical
negation of some other Adaptable Binary
Predicate.
 If f is a binary_negate object constructed
with predicate pred, then f(x,y) returns
!pred(x,y).
 The function not2 returns a binary_negate
object.
Example
struct U : public binary_function<U,U,bool> {
int id;
bool operator() (const U &x, const U &y) {
return x.id >= y.id;
}
};
Example 2
main() {
vector<U> v;
//Sort v in ascending order.
sort(v.begin(), v.end(), not2(U()));
}
Class mem_fun_t
 Class mem_fun_t is a function adaptor
that takes a member function with
signature R X::f() and makes it possible to
call it as if it were an ordinary function.
 If F is a mem_fun_t that was constructed
to use X::f and x is an X* pointer then F(x)
is equivalent to x->f().
 The function mem_fun returns a
mem_fun_t object.
Class mem_fun_t 2
 There are several similar function objects.
 The class const_mem_fun_t adapts a
member function of the form R X::f() const.
 The class mem_fun_ref_t has its
operator() take an X& argument. So that
F(x) is equivalent to x.f(). The
corresponding function is mem_fun_ref().
 The class const_mem_fun_ref_t adapts a
const member function.
Class mem_fun_t 3
template <class _Ret, class _Tp>
class mem_fun_t : public unary_function<_Tp*, _Ret>
{
public:
explicit
mem_fun_t(_Ret (_Tp::*__pf)())
: _M_f(__pf) {}
_Ret operator()(_Tp* __p) const
{ return (__p->*_M_f)(); }
private:
_Ret (_Tp::*_M_f)();
};
Class mem_fun_t 4
template <class _Ret, class _Tp>
inline mem_fun_t<_Ret, _Tp>
mem_fun(_Ret (_Tp::*__f)())
{ return mem_fun_t<_Ret, _Tp>(__f); }
Example
struct B {
virtual void print() = 0;
};
struct C: public B {
void print() { std::cout << "I'm a C\n"; }
};
struct D: public B {
void print() { std::cout << "I'm a D\n"; }
};
Example 2
main() {
std::vector<B*> vbp;
vbp.push_back(new C);
vbp.push_back(new D);
vbp.push_back(new C);
vbp.push_back(new D);
std::for_each(vbp.begin(), vbp.end(),
std::mem_fun(&B::print));
Example 3
std::vector<C> vb;
vb.push_back(C());
vb.push_back(C());
std::for_each(vb.begin(), vb.end(),
std::mem_fun_ref(&B::print));
Example 4
std::vector<std::vector<int> > vi;
vi.push_back(std::vector<int>(2));
vi.push_back(std::vector<int>(7));
vi.push_back(std::vector<int>(6));
transform(vi.begin(),vi.end(),
std::ostream_iterator<int>(std::cout, " "),
std::mem_fun_ref(&std::vector<int>::size));
std::cout << '\n';
Example 5
 Output
I'm a C
I'm a D
I'm a C
I'm a D
I'm a C
I'm a C
276
Class mem_fun1_t
 Class mem_fun1_t is a function adaptor that
takes a member function with signature R X::f(A)
and makes it possible to call it as if it were an
ordinary function.
 If F is a mem_fun1_t that was constructed to use
X::f, a is a value of type A and x is an X* pointer
then F(x) is equivalent to x->f(a).
 The function mem_fun returns a mem_fun1_t
object.
Class mem_fun1_t 2
 There are also function objects
mem_fun1_ref_t, const_mem_fun1_t, and
const_mem_fun1_ref_t.
STL Algorithms
for_each()
Function for_each(InputIterator beg, InputIterator end, Function f)
- Applies function f to each element in range [beg,end)
- Returns f
Nonmutating Algorithms
size_t count(InputIterator beg, InputIterator end, const T &val)
- Returns the number of occurrences of val in range [beg,end)
size_t count(InputIterator beg, InputIterator end, const T &val, Size &n)
- Adds the number of occurrences of val in [beg,end) to n
STL Algorithms 2
size_t count_if(InputIterator beg, InputIterator end, Predicate pred)
- Returns the number of elements in range [beg,end) for which
pred is true
InputIterator min_element(InputIterator beg, InputIterator end)
InputIterator max_element(InputIterator beg, InputIterator end)
- Returns the minimum or maximum element in range
[beg,end)
STL Algorithms 3
bool lexicographical_compare(InputIterator1 beg1,
InputIterator1 end1,
InputIterator2 beg2, InputIterator end2) (Bin. Pred.)
- Returns whether or not the elements in the range
[beg1,end1) are less than the elements in the range [beg2,end2)
Search Functions
InputIterator find(InputIterator beg, InputIterator end, const T &val)
- Finds and returns the first position of val in range [beg,end)
- Returns end if val not found
STL Algorithms 4
InputIterator adjacent_find(InputIterator beg,
InputIterator end) (Bin. Pred.)
- Finds and returns the first position in range
[beg,end) for which two consecutive elements are
equal
- Returns end if no match found
InputIterator find_if(InputIterator beg, InputIterator end,
Predicate pred)
- Finds and returns the first position in range
[beg,end) for which pred is true
- Returns end if no matching element found
STL Algorithms 5
InputIterator adjacent_find_if(InputIterator beg,
InputIterator end, Predicate pred)
- Finds and returns the first position in range [beg,end)
for which pred is true for two consecutive elements
- Returns end if no match found
InputIterator search_n(InputIterator beg, InputIterator end,
Size n, const T &val) (Bin Pred)
- Finds and returns the first position in range [beg,end)
for which n consecutive vals occur, in the first case
- Returns end if no matching element found
STL Algorithms 6
ForwardIterator1 search(ForwardIterator1 beg1, ForwardIterator1
end1, ForwardIterator2 beg2, ForwardIterator2 end2) (Bin Pred)
- Returns the position of the first element of the first subrange in
the range [beg1,end1) that matches all of the elements in the range
[beg2,end2)
- Returns end1 if no match found
ForwardIterator1 find_end(ForwardIterator1 beg1, ForwardIterator1
end1, ForwardIterator2 beg2, ForwardIterator2 end2) (Bin Pred)
- Returns the position of the first element of the last subrange in the
range [beg1,end1) that matches all of the elements in the range
[beg2,end2)
- Returns end1 if no match found
STL Algorithms 7
ForwardIterator1 find_first_of(ForwardIterator1 beg1,
ForwardIterator1 end1, ForwardIterator2 beg2,
ForwardIterator2 end2)
(Binary Pred)
- Returns the postion of the first element in the range
[beg1,end1) that is also in the range [beg2,end2)
- Returns end1 if no match found
bool equal(InputIterator1 beg1, InputIterator1 end1,
InputIterator2 beg2)
(Binary Pred)
- Returns whether or not the elements in the range
[beg1,end1) are equal to the corresponding elements in
the range [beg2,end2)
STL Algorithms 8
pair<InputIterator1, InputIterator2>
mismatch(InputIterator1 beg1, InputIterator1 end1,
InputIterator2 beg2)
(Binary Pred)
- Returns the first positions in the ranges starting with
beg1 and beg2 that are different
- Returns end1 if no mismatch found
Mutating Algorithms
Note: Associative containers cannot be used as the
destination of any of the following algorithms (because of
the underlying sort of these containers)
STL Algorithms 8
OutputIterator copy(InputIterator sourceBeg,
InputIterator sourceEnd, OutputIterator destBeg)
- Copies the range [sourceBeg,sourceEnd) to
the range starting at position destBeg,
overwriting the elements already there (no
memory is allocated, unless insert iterators are
used)
- The source and destination may overlap
- Returns the position in the destination after
the last element copied
STL Algorithms 9
BidirectionalIterator copy_backward(InputIterator
sourceBeg, InputIterator sourceEnd,
BidirectionalIterator destEnd)
- Copies the range [sourceBeg,sourceEnd) to
the range starting at position destEnd (moving
backwards through the destination, so that the
elements end up in the same order as the
source). Elements are overwritten (no memory is
allocated, unless insert iterators are used)
- The source and destination may overlap
- Returns the position in destination before the
last element copied
STL Algorithms 10
OutputIterator transform(InputIterator sourceBeg,
InputIterator sourceEnd,
OutputIterator destBeg, Function f)
- Applies the function f to each element of source
range and copies the return value of the function to the
destination (no memory is allocated, unless insert
iterators are used)
- The source and destination ranges may be the same
- Returns the position after the last element copied
STL Algorithms 11
OutputIterator transform(InputIterator1 source1Beg,
InputIterator1 source1End,
InputIterator2 source2Beg, OutputIterator destBeg,
BinaryFunction f)
- Applies the binary function f to the corresponding
elements of the two source ranges and copies the return
value to the destination (no memory is allocated, unless
insert iterators are used)
- The source and destination ranges may be the same
- Returns the position after the last element copied
STL Algorithms 12
ForwardIterator2 swap_ranges(ForwardIterator1 beg1,
ForwardIterator1 end1, ForwardIterator2 beg2)
- Swaps the elements in the ranges beginning with
beg1 and beg2
- Returns the position after the last swapped element
in second range
void fill(ForwardIterator beg, ForwardIterator end, const T
&val)
- Assigns val to the elements in the range [beg,end)
STL Algorithms 13
void fill_n(OutputIterator pos, Size n, const T &val)
- Assigns val to the first n elements beginning at
position pos
- Destination must be large enough (else insert
iterators must be used)
void generate(ForwardIterator beg, ForwardIterator end,
Function f)
- Assigns the output of function f to the elements in
range [beg,end)
- Note: the elements are not used as input to f (as in
the transform algorithm)
STL Algorithms 14
void generate_n(OutputIterator pos, Size n,
Function f)
- Assigns the output of f to the n elements
beginning at position pos
void replace(ForwardIterator beg, ForwardIterator
end, const T &old_val, const T &new_val)
- Replaces each instance of old_val with
new_val in the range [beg,end)
STL Algorithms 15
void replace_if(ForwardIterator beg, ForwardIterator end,
Predicate pred, const T &new_val)
- Replaces each element in the range [beg,end) which
makes pred true with new_val
void replace_copy(ForwardIterator beg, ForwardIterator
end, OutputIterator destBeg, const T &old_val, const T
&new_val)
- Copies source range to destination range, in the
process it replaces each instance of old_val with
new_val in the destination range
STL Algorithms 16
void replace_copy_if(ForwardIterator beg,
ForwardIterator end, OutputIterator destBeg,
Predicate pred, const T &new_val)
- Copies source range to destination range, in
the process it replaces each element that makes
pred true with new_val in the destination range
STL Algorithms 17
Removing Algorithms
ForwardIterator remove(ForwardIterator beg,
ForwardIterator end, const T &val)
- "Removes" all elements in the range equal to
val
- The "removed" elements are moved to
positions after return position.
- The function returns the position after the
last element not removed
STL Algorithms 18
ForwardIterator remove_if(ForwardIterator
beg, ForwardIterator end, Predicate pred)
- "Removes" all elements in the range
for which predicate is true
- The "removed" elements are moved to
positions after return position.
- The function returns the position after
the last element not removed
STL Algorithms 19
OutputIterator remove_copy(InputIterator
sourceBeg, InputIterator sourceEnd,
OutputIterator destBeg, const T &val)
- Copies source range to destination range, in
the process not copying any elements in the
source range equal to val.
- Destination must be large enough (else
insert iterators must be used)
- Returns position after last copied element in
the destination
STL Algorithms 20
OutputIterator remove_copy_if(InputIterator
sourceBeg, InputIterator sourceEnd,
OutputIterator destBeg, Predicate pred)
- Copies source range to destination range, in
the process not copying any elements in the
source range which make predicate true
- Destination must be large enough (else
insert iterators must be used)
- Returns position after last copied element in
the destination
STL Algorithms 21
ForwardIterator unique(ForwardIterator beg,
ForwardIterator end)
(Binary Pred)
- "Removes" the second of consecutive
equal elements in the range [beg,end)
- The "removed" elements are moved to
positions after return position.
- The function returns the position after
the last element not removed
STL Algorithms 22
OutputIterator unique_copy(InputIterator
sourceBeg, InputIterator sourceEnd,
OutputIterator destBeg)
(Binary Pred)
- Copies source range to destination range, in
the process not copying consecutive duplicates.
- Destination must be large enough (else
insert iterators must be used)
- Returns position after last copied element in
the destination
STL Algorithms 23
Reordering Algorithms
void reverse(BidirectionalIterator beg,
BidirectionalIterator end)
- Reverses the elements in the range
[beg,end)
STL Algorithms 24
void rotate(ForwardIterator beg, ForwardIterator
newBeg, ForwardIterator end)
- Rotates elements in range [beg,end) so that
the element that was in position newBeg is now
in position beg
STL Algorithms 25
OutputIterator rotate_copy(ForwardIterator beg,
ForwardIterator newBeg, ForwardIterator end,
OutputIterator destBeg)
- Copies the elements from source range to
the destination, in the process rotating the
elements so that the element in position newBeg
ends up in position destBeg
- Destination must be large enough (else
insert iterators must be used)
- Returns position after last copied element in
the destination
STL Algorithms 26
bool next_permutation(Bidirectional beg,
Bidirectional end)
- Permutes the elements in range [beg,end)
using the next permutation of the elements in
the lexicographical ordering of all permutations.
- If such a permutation exists it returns true,
otherwise it sorts the sequence in ascending
order and returns false
STL Algorithms 27
bool prev_permutation(Bidirectional beg,
Bidirectional end)
- Permutes the elements in range
[beg,end) using the previous permutation
of the elements in the lexicographical
ordering of all permutations.
- If such a permutation exists it returns
true, otherwise it sorts the sequence in
descending order and returns false
STL Algorithms 28
void random_shuffle(RandomAccessIterator beg,
RandomAccessIterator end)
void random_shuffle(RandomAccessIterator beg,
RandomAccessIterator end, RandomFunc f)
- Shuffles the elements in the range [beg,end),
in the first case using the standard library
random number generator, and in the second
case using a user-supplied random number
generator f.
STL Algorithms 29
BidirectionalIterator partition(BidirectionalIterator
beg, BidirectionalIterator end, Predicate pred)
BidirectionalIterator
stable_partition(BidirectionalIterator beg,
BidirectionalIterator end, Predicate pred)
- Moves all elements in the range [beg,end)
for which predicate is true up to the beginning of
the range
- The second function preserves the relative
order of the matched and the unmatched
elements.
STL Algorithms 30
Sorting Algorithms
void sort(RandomAccessIterator beg,
RandomAccessIterator end) (Binary Pred)
void stable_sort(RandomAccessIterator beg,
RandomAccessIterator end) (Binary Pred)
- Sorts the elements in the range [beg,end)
- The second function maintains the relative
order of equal elements
STL Algorithms 31
void partial_sort(RandomAccessIterator
beg, RandomAccessIterator sortEnd,
RandomAccessIterator end) (Bin Pred)
- After this function the elements in the
range [beg,sortEnd) are in the correct
order that they would be in if the entire
range [beg,end) were sorted
STL Algorithms 32
RandomAccessIterator
partial_sort_copy(InputIterator beg1,
InputIterator end1, RandomAccessIterator beg2,
RandomAccessIterator end2) (Binary Pred)
- This takes the elements in range
[beg1,end1) and copies them in sorted order to
the range [beg2,end2)
- The number of elements that are sorted and
copied is the minimum of the source and
destination ranges
- Returns position after last copied element in
the destination
STL Algorithms 33
void nth_element(RandomAccessIterator
beg, RandomAccessIterator nth,
RandomAccessIterator end) (Bin Pred)
- Rearranges range [beg,end) so that
the correct element is in position n (in
sorted order) and the elements to the right
are greater or equal and the elements to
the left are less than or equal
STL Algorithms 34
Sorted Range Algorithms
All of the following algorithms assume that
the range is already sorted
bool binary_search(ForwardIterator beg,
ForwardIterator end, const T &val)
(Binary Pred)
- Returns whether or not val is in the
range [beg,end)
STL Algorithms 35
bool includes(InputIterator beg1,
InputIterator end1,
InputIterator beg2, InputIterator end2)
(Binary Pred)
- Returns whether or not the sorted
range [beg2,end2) is found exactly as is in
the sorted range [beg1,end1)
STL Algorithms 36
ForwardIter lower_bound(ForwardIter beg,
ForwardIter end, const T &val)
(BinaryPred)
ForwardIter upper_bound(ForwardIter beg,
ForwardIter end, const T &val)
(Binary Pred)
- lower_bound() returns the position of the first
occurrence of val
- upper_bound() returns the position of the first
element greater than val
STL Algorithms 37
pair<ForwardIter,ForwardIter>
equal_range(ForwardIter beg, ForwardIter
end, const T &val)
(Binary Pred)
- Returns iterators to the first element
equal and the first element greater than
val
STL Algorithms 38
OutputIterator merge(InputIterator1 source1Beg,
InputIterator1 source1End,
InputIterator2 source2Beg, InputIterator
source2End, OutputIterator destBeg) (Binary Pred)
- Merge the two source ranges and copy it to the
destination range
- Destination must be large enough (else insert
iterators must be used)
- Returns position after last copied element in the
destination
STL Algorithms 39
Numeric Algorithms
T accumulate(InputIterator beg,
InputIterator end, T initVal)
T accumulate(InputIterator beg,
InputIterator end, T initVal, BinaryOp op)
- Returns the sum of initVal plus all the
elements in range [beg,end)
STL Algorithms 40
OutputIterator partial_sum(InputIterator
sourceBeg, InputIterator sourceEnd,
OutputIterator destBeg)
(Binary Pred)
- Calculates the partial sums for the elements
in source range and copies them over to the
destination range
- If x1, x2, x3, ... are the source values then
x1, x1+x2, x1+x2+x3, ... are the values copied to
the destination
STL Algorithms 41
Set Operations
template <class InputIterator1, class InputIterator2,
class OutputIterator> OutputIterator set_union (
InputIterator1 first1, InputIterator1 last1,
InputIterator2 first2, InputIterator2 last2,
OutputIterator result );
(Bin Pred)
- Constructs a sorted range beginning in the
location pointed by result with the set union of
the two sorted ranges [first1,last1) and
[first2,last2) as content.
STL Algorithms 42
template <class InputIterator1, class InputIterator2,
class OutputIterator> OutputIterator
set_difference ( InputIterator1 first1,
InputIterator1 last1, InputIterator2 first2,
InputIterator2 last2, OutputIterator result ) (Bin
Pred)
- Constructs a sorted range beginning in the
location pointed by result with the set difference
of range [first1,last1) with respect to [first2,last2)
as content.
STL Algorithms 43
template <class InputIterator1, class InputIterator2,
class OutputIterator> OutputIterator
set_symmetric_difference ( InputIterator1
first1, InputIterator1 last1, InputIterator2 first2,
InputIterator2 last2, OutputIterator result ) (Bin
Pred)
- Constructs a sorted range beginning in the
location pointed by result with the set symmetric
difference of the two sorted ranges [first1,last1)
and [first2,last2) as content.
STL Algorithms 44
template <class InputIterator1, class InputIterator2,
class OutputIterator> OutputIterator
set_intersection ( InputIterator1 first1,
InputIterator1 last1, InputIterator2 first2,
InputIterator2 last2, OutputIterator result ) (Bin
Pred)
- Constructs a sorted range beginning in the
location pointed by result with the set
intersection of the two sorted ranges [first1,last1)
and [first2,last2) as content.
Download