Debugging
There
are programs to help you find runtime error
You
program must compile to use a debugger
In
the lab tomorrow, you will be introduced to GDB, the GNU debugger
This is certainly not the best debugger available, but
from it you can at least learn what a debugger can do.
I urge you to explore other debuggers.
Online
references for GDB
The Standard
Template Library
General Overview
The STL is a generic library
that provides solutions to
managing collections of data
with modern and efficient
algorithms.
From a programmers point a view, the STL
provides a bunch of collection classes that meet different needs, as well as
algorithms that operate on them.
Using it means you can forget programming
Dynamic arrays
Linked lists
Binary trees
Different search or sort algorithms
But all this programming power comes at a
priceit is not especially easy to learn to use.
STL Components
Containers
These
are data structures designed to hold or contain data
Every
kind of container has its own advantages and disadvantages
They
may be implemented as arrays, linked lists or trees
Iterators
These
are smart pointers
They step through an array the same way they step
through a linked list or a tree
The
interface is much like pointers
Increment using the ++ operator
Dereference use the * operator
Every
container class provides it own iterator type that knows the internal structure
of its container
Algorithms
These
are global functions used to process the elements of containers.
Usually
the first two arguments are iterators denoting a range
They
search, sort, modify, or otherwise use the elements
Example: prints all the elements of a list container
/* The following code example is taken
from the book "The
C++ Standard Library - A Tutorial and Reference" (C) Copyright Nicolai
M. Josuttis 1999. */
#include <iostream>
#include <list>
using namespace std;
int main( )
{ list<char> coll;
// instantiates the list container for character elements
for (char c='a'; c<='z';
++c) // append elements from 'a' to
'z'
{
coll.push_back(c);
}
/* print all elements * pos iterates over all
elements */
list<char>::const_iterator pos; // instantiate the iterator
for (pos = coll.begin(
); pos != coll.end( ); ++pos)
{ cout <<
*pos << ' ';
}
cout << endl;
}
int
main()
{ vector<int>
coll;
//instantiates a vector of ints
vector<int>::iterator pos; // instantiates an iterator for vectors
// insert elements from 1 to 6 in arbitrary
order
coll.push_back(2); coll.push_back(5); coll.push_back(4); coll.push_back(1); coll.push_back(6); coll.push_back(3);
// find and print minimum and
maximum elements
pos = min_element
(coll.begin( ), coll.end(
));
cout << "min: " << *pos
<< endl;
pos = max_element (coll.begin( ), coll.end( ));
cout << "max: " << *pos
<< endl;
// sort all elements
sort (coll.begin( ), coll.end( ));
pos = find (coll.begin( ), coll.end( ), 3);
// reverse the order of the found
element with value 3 and all following elements
reverse (pos, coll.end( )); //pos is the beginning iterator
// print all elements
for
(pos=coll.begin( ); pos!=coll.end(
); ++pos)
{ cout
<< *pos << ' '; }
cout
<< endl;
}
Containers
These are class templates that have member functions to manage the elements
Two general kinds of containers
Sequence container
These are collections whose
position depends on time and
place of insertion
The position is independent of
the elements value
Associative containers
These are sorted collections
The actual position of an element depends on its value
due to a certain sorting criterion
Iterators
An
iterator represents a certain position in a container
All
iterators are defined with these fundamental operations
Operator
++ step forward to the next
element
Operators
= = and !=
equal and not equal
Operator
= the assignment operator
Operator
* dereferences
So
the interface to iterators is like a pointer interface (i.e. they are used the
same)
Ordinary
pointers may be used in place of iterators if convenient (as arguments for
algorithms)
An
iterators is a class nested inside the collection class template
The user
must instantiate objects
of the iterator class to use them.
There
are different types of
interators, depending on the class
through which they iterate
Container class member functions
begin( )
Returns
an iterator that is the beginning position of the first element of the
container
end( )
Returns an iterator that is one byte past the end of the
elements in the container.
This
is also call a past-the-end iterator
size( )
Returns
the number of items in the container
empty( )
Returns
true if the container is empty
push_back ( )
Adds
an element to the end of a sequential container
Algorithms
These
are global function templates that operate on containers through
iterators
They
are designed to work with STL containers, but can be applied to ordinary C++
arrays.
The
first two args are a pair of iterators (first,
last) marking off the range of elements in the container over which to
operate
The
elements are usually written [first, last)
It
must be possible to reach last
beginning with first
through repeated application of the increment operator
Different
algorithms require different iterator types
The
minimum category of iterator is indicated in documentation
Example:
find( ) requires a one-pass, read-only iterator;
iterators that do more (bidirectional, random access) work as well.
Some
algorithms have multiple versions with different arguments
For
those algorithms that modify the container over which they operate,
there are generally two versions i.e. replace( ) and replace_copy( )
Some simplified STL algorithms
iter copy (iter first, iter last, iter result);
Copies
[first, last), putting copy at result; returns pointer one past the end of the
resulting sequence
Note: it is always an error to dereference last
iter find (iter
first, iter last, const T &val);
Searches
[first,last) for val;
returns an iterator to the first occurrence of the element
or to end if the value is not in the sequence
iter find_if (iter first, iter last, predicate pred);
A
predicate is a function that returns T or F
Examines
[first, last) applying predicate to each element; If pred
returns true, the search ends, returning an iterator to the element
void
for_each (iter first, iter
last, function);
Applies
the function to each element of the container
iter
max_element (iter first, iter
last);
Returns
an iterator to the maximum element within the range
iter sort (iter first, iter last);
Sorts
the specified range
Member functions vs. global algorithms
Often
a container has a member function that does the same thing as an algorithm, but
with much better performance
An
example is the global remove( )
algorithm
remove( ) reorders the elements by changing
their values
So
if the first element is removed, then all the following elements are assigned
to their previous elements
This
is an extremely inefficient way to remove an element from a linked list, but
the only way to remove from an array
remove( ) doesnt
know if it is operating on a list
it always does the same thing
The
list container class provides special member functions for all the algorithms
that manipulate elements in the list.
For
example, global sort( ) will not work with list
containers, since it requires a random access iterator. Instead, use the sort(
) member function.
The sequence containers
Vectorsimplemented
as a dynamic array
Dequesa
double ended queue;
Lists
implemented as a doubly linked list
In
addition, you can use strings and ordinary arrays as sequence
containers
The vector container--how it is implemented
Implemented as a dynamic array(size depends on implementation)
To use a vector you must include the
header file #include <vector>
Vectors
provide good performance if you insert or delete elements at the end
When you insert or delete in the middle or
beginning, every element behind has to be moved to another position
The
iterators are random access, so you can use any algorithm of the STL
Any
object that will be stored in a vector must define a default constructor.
It
must also define the < and == operations
You
can use array subscripting to access or modify vector elements
No
range checking done with [ ]
Use
the at( ) member function for range
checking
Allocating memory for vectors
When
you declare a vector, more memory is dynamically allocated than needed to
contain all the elements of a vector
If
your vector grows larger than this amount, reallocation is necessary
The
entire vector must be copied into a larger space. Obviously this takes time.
It
also invalidates all references, pointers and iterators for elements of the
vector
Size
and Capacity
the size( )
member function returns the number of elements in your vector
the capacity( )
member function returns the number of items a vector could contain without reallocation
If
you exceed the capacity( ), the vector has to reallocate
its internal memory
To avoid reallocation, you can use reserve( ) to ensure a certain capacity before you really
need it. EX: v.reserve(80)
Deque containers
To use a deque you must include the
header file #include <deque>
Implemented as dynamic arrays, typically
a bunch of individual blocks, growing in opposite directions
The interface of vectors and deques is almost the same
Inserting or deleting at either end of a
deque is efficient
Inserting or deleting in the middle of a deque is
inefficient, but can be done (same as for vectors)
List containers
Implemented as a doubly linked list
Does not provide random access
So
no subscript operator nor at( )
Cannot use algorithms that require random access
iterators
No operations for capacity or
reallocation
Many special member
functions for inserting, deleting and moving elements.
They are faster than the global algorithms with the same names.
To
use a list you must include the header file #include <list>
Some Sequential Container member
functions
Vectors
push_back( ) --automatically
increase vector size if necessary
(cannot
use push_fronttoo inefficient)
size( ) returns size
max_size ( ) system dependent
swap ( ) swap contents of vectors
empty ( ) returns boolean
back ( ) return last element
pop_back ( ) - remove last element
insert(iterator, value ) not too efficient for vectors
erase( iterator) - not efficient
Lists
push_back( )
push_front
size( )
front( ) or back( ) return items
pop_front( )
pop_back( )
insert( ) 3 versions
erase( )
reverse( )
merge( list)
unique( ) removes duplicates
Associative containers
Sets & Multisets
These containers sort their elements automatically
according to a certain sorting criterion
The difference is that multisets
allow duplicates; sets do not
Maps & Multimaps
These containers manage key/value pairs as elements
They also sort their elements automatically according
to some sorting criterion that is used for the key
The difference is that maps do not allow duplicates,
while multimaps do
Pairs
The class pair is provided to treat two values as a
single unit.
It has two data members, first and second
It is used by maps and multimaps
to manage their elements