Standard Template Library Quick Reference: Containers
Standard Template Library Quick Reference: Containers
Containers
Containers are general-purpose template classes that are designed to store
objects of almost any type. They are useful by themselves, but become even
more powerful when combined with other concepts such as iterators and
algorithms.
Standard Containers
NOTE: The Alloc parameter allows you to define your own custom memory
allocator if needed. A custom memory allocator is useful is some situations such
as when working with embedded systems which do not have general-purpose
malloc/free or new/delete operators.
Vector Advantages
– Vectors can be dynamically resized; when you run out of space it automatically
grows
– Elements of a vector can be added or removed from the interior without needing
to write custom code
– You can quickly access the start the or end of the vector, without knowing it
size in advance
– You can iterate forward or backward through a vector
– It is a simple matter to add bounds checking for both operator[] and pointer
dereferencing
– Objects in a vector can be stored in any kind of memory with the help of a
custom allocator
– Unlike standard arrays, vector have usable assignment and comparison
operators.
Vector Disadvantages
Deque Advantages
– Since a deque acts a lot like a vector, it has the same advantages as using a
vector when compared to standard C-style arrays
– It can grow in either direction (front or back) equally well
– It is often faster than a vector when the container needs to grow to hold new
elements
Deque Disadvantages
– The operator[] is not as fast as vector's operator[], although it is still pretty fast
– Iterating over a deque is also slower than iterating over a vector
List Advantages
List Disadvantages
General Guideline
Use a vector<> whenever possible since it has the lowest overhead and best
overall performance. However, if you are going to add and removing items from
the middle of the collection often, then consider using a list<>. Use a deque<>
whenever you will be inserting elements at the head or end most of the time, but
very seldom from the middle of the collection.
Container Adapters
The following containers are specialized containers that use one of the standard
containers to actually store the elements they manage. Basically they are
wrappers around one of the standard container templates that provide a restricted
set of operations.
Associative Containers
Iterator Categories
Algorithm Types
Non-Mutating Algorithms
Remember, the non-mutating algorithms never modify the containers they are
working on.
Algorithm Description
UnaryFunction Iterates all of the elements from
first to last and calls function f
for_each( InputIterator first,
once per element. The return
InputIterator last, value is sometimes useful when
UnaryFunction f) dealing with functors.
InputIterator Attempts to locate value in the
elements pointed to by first and
find( InputIterator first,
last. The value is usually the
InputIterator last, same type as the elements in the
const EqualityComparable& value) container, but conversions are
performed if needed. Returns an
iterator that points to the first
match if found. Returns last if the
item cannot be found.
Algorithm Description
InputIterator Similar to the find() algorithm,
except instead of comparing
find_if(InputIterator first,
values directly, it passes each
InputIterator last, element in the range to a helper
Predicate pred) function (or functor) that tests the
object in some way and returns a
boolean value. If the helper
function returns true, the search
stops and an iterator to the
element is returned, otherwise last
is returned.
ForwardIterator This function iterates over the
container's elements to locate the
adjacent_find( ForwardIterator first,
first of 2 iterators that are valid.
ForwardIterator last) The first version is not very useful,
the second works like find_if() so
ForwardIterator
you can call a custom function (or
adjacent_find( ForwardIterator first, functor) that tests adjacent
ForwardIterator last, elements and returns a boolean.
BinaryPredicate binary_pred )
InputIterator Similar to using find(), except this
algorithm searches the first
find_first_of( InputIterator first1,
sequence to find any element that
InputIterator last1, is also in a second sequence.
ForwardIterator first2,
ForwardIterator last2) The second version of the function
allows you to use a custom
InputIterator
function (or functor) instead of the
find_first_of( InputIterator first1, standard operator==().
InputIterator last1,
ForwardIterator first2,
ForwardIterator last2,
BinaryPredicate comp)
Algorithm Description
iterator_traits<InputIterator>::difference_type This algorithm iterators over a
sequence and counts the number
count( InputIterator first,
of elements that match the given
InputIterator last, value.
const EqualityComparable& value)
void The first version returns the
number of matches found, while
count( InputIterator first,
the second version adds the
InputIterator last, number of matches to the value
const EqualityComparable& value, referenced by n.
Size& n )
The second version is deprecated
and may be removed later.
iterator_traits<InputIterator>::difference_type Similar to the count() algorithm,
but instead of comparing the
count_if( InputIterator first,
elements to some value, passes
InputIterator last, each element to a helper function
Predicate pred) (or functor) and only counts
elements where the helper
void function returns true.
count_if( InputIterator first,
InputIterator last, The second version is deprecated
Predicate pred, and may be removed later.
Size& n)
pair<InputIterator1, InputIterator2> Searches the sequence
references by first1 and last1 to
mismatch( InputIterator1 first1,
find an element that does not
InputIterator1 last1, match the elements in first2. In
InputIterator2 first2 ) other words, finds the first
difference between 2 containers.
pair<InputIterator1, InputIterator2>
mismatch( InputIterator1 first1,
The second versions of the
InputIterator1 last1, algorithm allows you to use a
InputIterator2 first2, custom function (or functor) to
compare the elements in the
BinaryPredicate binary_pred ) containers.
Algorithm Description
bool Similar to the mismatch()
algorithm, except this algorithm
equals( InputIterator first1,
simply returns true or false to
InputIterator last1, indicate whether the 2 sequences
InputIterator2 first2 ) are equal or not.
bool
Can also be done using:
equals( InputIterator first1,
mismatch(f1,l1,f2).first == l1
InputIterator last1,
InputIterator2 first2,
BinaryPredicate binary_pred )
ForwardIterator1 These algorithms attempt to find
the sequence first2->last2
search( ForwardIterator1 first1,
somewhere instead the sequence
ForwardIterator1 last1, first1->last1.
ForwardIterator2 first2,
ForwardIterator2 last2 ) This works a bit like searching for
a substring within a larger string,
ForwardIterator1
except of course the elements can
search( ForwardIterator1 first1, be of any type, not just characters.
ForwardIterator1 last1,
ForwardIterator2 first2,
ForwardIterator2 last2,
BinaryPredicate binary_pred )
ForwardIterator Attempts to find the position in the
sequence where value is repeated
search_n( ForwardIterator first,
count times in a row. Useful for
ForwardIterator last, testing for repeated elements.
Integer count,
const T& value ) NOTE: Using 0 for count will
always succeed, no matter the
ForwardIterator
value, since there will be no
search_n( ForwardIterator first, comparisons performed.
ForwardIterator last,
Integer count,
const T& value,
BinaryPredicate binary_pred )
Algorithm Description
ForwardIterator1 Works similar to search().
Probably should be named
find_end( ForwardIterator1 first1,
search_end().
ForwardIterator1 last1,
ForwardIterator2 first1,
Instead of returning the first match
ForwardIterator2 last2 ) in the search, this algorithm
returns an iterator that points to
ForwardIterator1
the last match instead.
find_end( ForwardIterator1 first1,
ForwardIterator1 last1,
ForwardIterator2 first2,
ForwardIterator2 last2,
BinaryPredicate binary_pred )
Mutating Algorithms
The mutating algorithms are used to make changes to containers or the elements
inside a container.
Algorithm Description
OutputIterator This algorithm copies the
elements referenced by first->last
copy( InputIterator first,
by overwriting the elements in
InputIterator last, result.
OutputIterator result ) NOTE; The output container must
be large enough to hold all the
copied elements, since this
algorithm assigns the copied
elements, it does not push them.
BidirectionalIterator2 Also copies the elements from
first->last into the container at
copy_backward( BidirectionalIterator1 first,
result, but copies from last to first
BidirectionalIterator1 last, in backward sequence.
BidirectionalIterator2 result )
NOTE: result must point to the
end of the sequence, not the
beginning.
void swap( Assignable& a, Assignable& b ) Assigns a to b and b to a.
Algorithm Description
void swap_iter( ForwardIterator1 a, Same as swap( *a, *b ).
ForwardIterator2 b )
OutputIterator
unique_copy( InputIterator first,
InputIterator last,
OutputIterator result,
BinaryPredicate binary_pred )
void Reverses a container so the last
element becomes the first and
reverse( BidirectionalIterator first,
the first element becomes the
BidirectionalIterator last ) last and so on.
OutputIterator Copies elements first->last into
container result, in reverse
reverse_copy( BidirectionalIterator first,
sequence.
BidirectionalIterator last,
OutputIterator result )
ForwardIterator Rearranges the container so
middle becomes first and last
rotate( ForwardIterator first,
becomes middle. This means
ForwardIterator last, first also becomes middle+1.
ForwardIterator middle ) Acts like rotating a circle.
OutputIterator Works like rotate(), except
copies the rotated elements into
rotate_copy( ForwardIterator first,
result. Faster then doing a copy
ForwardIterator middle, () followed by a rotate().
ForwardIterator last,
OutputIterator result )
void Randomly rearranges all the
random_shuffle( RandomAccessIterator first, elements in first->last. The
second version allows you to use
RandomAccessIterator last ) a custom random number
generator functor.
void
random_shuffle( RandomAccessIterator first,
RandomAccessIterator last,
RandomNumberGenerator& rand )
Algorithm Description
RandomAccessIterator Works like the random_shuffle()
algorithm, except instead of
random_sample( InputIterator first,
rearranging the input container,
InputIterator last, copies the elements randomly
RandomAccessIterator ofirst, into another container. Each
input element will only appear
RandomAccessIterator olast ) once in the output, in random
RandomAccessIterator sequence.
Distance n )
OutputIterator
random_sample_n( ForwardIterator first,
ForwardIterator last,
OutputIterator out,
Distance n,
RandomNumberGenerator& rand )
ForwardIterator This algorithm rearranges the
elements in first->last by calling
partition( ForwardIterator first,
the helper function (or functor)
ForwardIterator last, pred against each element. All
Predicate pred ) elements where pred returns true
are placed before the elements
that return false. The returned
iterator will point to the middle.
(i.e. The first false element.)
Algorithm Description
ForwardIterator Same as partition(), except the
elements will maintain their
stable_partition( ForwardIterator first,
relative order within the
ForwardIterator last, sequence.
Predicate pred )
Sorting Algorithms
This group of algorithm are used to fully or partially sort the elements in a
container.
Algorithm Description
void Rearranges the container so the
elements are in sorted sequence.
sort( RandomAccessIterator first,
By default, it uses operator<() to
RandomAccessIterator last ) compare elements.
void
sort( RandomAccessIterator first, The second version allows you to
use a helper function (or function)
RandomAccessIterator last,
to get custom sort sequences.
Compare comp )
void Also sorts elements in a
container, but unlike the standard
stable_sort( RandomAccessIterator first,
sort(), this one preserves the
RandomAccessIterator last ) relative order of duplicate
elements. This means that
void
stable_sort() is less efficient
stable_sort( RandomAccessIterator first, than standard sort().
RandomAccessIterator last,
Compare comp )
Algorithm Description
void This algorithm also sorts
elements in containers, but in this
partial_sort( RandomAccessIterator first,
case only elements from first-
RandomAccessIterator middle, >middle are sorted and placed at
RandomAccessIterator last ) the beginning of the container.
The elements from middle->last
void are unsorted (and probably
partial_sort( RandomAccessIterator first, rearranged).
RandomAccessIterator middle,
RandomAccessIterator last,
Compare comp )
RandomAccessIterator This algorithm combines partial
sorting with copying of the
partial_sort_copy( InputIterator first,
elements. It will stop whenever it
InputIterator last, processes (last-first) or
RandomAccessIterator result_first, (result_last-result_first) elements,
whichever is smaller.
RandomAccessIterator result_last )
RandomAccessIterator
Useful for extracting X number of
partial_sort_copy( InputIterator first, items (perhaps the smallest or
InputIterator last, largest values) from a large
container into a smaller one.
RandomAccessIterator result_first,
RandomAccessIterator result_last,
Compare comp )
bool Returns true if the range is
already sorted, false otherwise.
is_sorted( ForwardIterator first,
ForwardIterator last )
bool
is_sorted( ForwardIterator first,
ForwardIterator last,
Compare comp )
Algorithm Description
void This is a special kind of partial
sort that ensures elements to the
nth_element( RandomAccessIterator first,
left of nth are less than all
RanomAccessIterator nth, elements to the right of nth. The
RandomAccessIterator last ) left side may or may not be
sorted. The same applies to the
void right side. However, all items to
nth_element( RandomAccessIterator first, the left will be less than the items
to the right, with nth used as a
RandomAccessIterator nth, split point.
RandomAccessIterator last,
Compare comp )
Searching Algorithms
Algorithm Description
ForwardIterator This algorithm performs a fast
binary search of a sorted
lower_bound( ForwardIterator first,
container and returns the iterator
ForwardIterator last, where a new element of value
const T& value ) can be inserted to maintain the
proper order of elements.
ForwardIterator
Uses operator<() by default, but
lower_bound( ForwardIterator first, the second version can be used
ForwardIterator last, to customize the comparison.
Merging Algorithms
There are a couple of algorithms you can use for combining and merging sorted
containers together.
Algorithm Description
OutputIterator Combines 2 sorted containers
(first1->last1 and first2->last2)
merge( InputIterator1 first1,
into another container (result) so
InputIterator1 last1, that the output container is also
InputIterator2 first2, sorted. The merge is stable,
which means the relative order of
InputIterator2 last2, duplicate elements is preserved.
OutputIterator result )
OutputIterator
merge( InputIterator1 first1,
InputIterator1 last1,
InputIterator2 first2,
InputIterator2 last2,
OutputIterator result,
Compare comp )
void This algorithm takes a container
that has been partially sorted
inplace_merge( BidirectionalIterator first,
(split around middle) and
BidirectionalIterator middle, completes the sort so the entire
BidirectionalIterator last ) container is now sorted.
void
inplace_merge( BidirectionalIterator first,
BidirectionalIterator middle,
BidirectionalIterator last,
Compare comp )
Set Algorithms
There are also a set of algorithms designed specifically for performing set
operations. Most of these algorithms do not require a set<> container, but they
may be used to implement the set<> template class.
Algorithm Description
bool Tests 2 sorted ranges to
determine if all of the elements in
includes( InputIterator1 first1,
first2->last2 are also found in
InputIterator1 last1, first1->last1. Returns true only if
InputIterator2 first2, all of the elements in the second
container can be found in the first
InputIterator2 last2 ) container.
bool Both input containers must be
includes( InputIterator1 first1, sorted for this algorithm to work
properly.
InputIterator1 last1,
InputIterator2 first2,
InputIterator2 last2,
Compare comp )
OutputIterator Copies all the sorted elements
that are in either first1->last1 or
set_union( InputIterator1 first1,
first2->last2 into a new container
InputIterator1 last1, (result), while preserving the sort
InputIterator2 first2, sequence.
Heap Operations
A heap is data structure similar to a tree, but normally stores its elements as an
array (including vector and deque). The difference is that in a heap not every
element has to be perfectly sorted. Instead the elements have to arranged so the
highest value is always above the lower values. This is used by the
priority_queue<> template internally to arrange elements by value.
Algorithm Description
Void Turns the container first->last into a
heap. Typically the underlying
make_heap( RandomAccessIterator first,
container will be a C-style array,
RandomAccessIterator last) vector<> or deque<> object.
void
make_heap( RandomAccessIterator first,
RandomAccessIterator last,
Compare comp )
Algorithm Description
void This function moves an element
that has already been added to the
push_heap( RandomAccessIterator first,
end of a container into its proper
RandomAccessIterator last ) location within the heap structure.
You must add the element to the
void
underlying container yourself,
push_heap( RandomAccessIterator first, perhaps by using the push_back()
RandomAccessIterator last, function.
Compare comp )
void This method removes the largest
element from the heap structure
pop_heap( RandomAccessIterator first,
(the largest element is normally the
RandomAccessIterator last ) first element). It does not actually
remove the element, but instead
void
moves it to the end of the
pop_heap( RandomAccessIterator first, underlying container and
RandomAccessIterator last, reorganizes the remaining
elements so the heap is still valid.
Compare comp )
void Returns the heap's underlying
heap sequence back into a sorted
sort_heap( RandomAccessIterator first,
sequence. The relative order of
RandomAccessIterator last ) the elements is not guaranteed to
be preserved.
void
sort_heap( RandomAccessIterator first,
RandomAccessIterator last,
Compare comp )
bool Tests a container to determine if it
is already organized into the
is_heap( RandomAccessIterator first,
sequence needed to be treated as
RandomAccessIterator last ) a heap structure.
bool
is_heap( RandomAccessIterator first,
RandomAccessIterator last,
Compare comp )
Miscellaneous Algorithms
OutputIterator
Output[0] = Input[0]
adjacent_difference( InputIterator first,
Output[i] = Input[i] – Input[i-1]
InputIterator last,
OutputIterator result )
Function Objects (aka Functors)
A function object or functor is any object that can be used as if it were a plain old
function. A class can used as a functor if it defines operator(), which is
sometimes referred to as the default operator. So a functor is really either a
pointer to a static function, or a pointer to an object that defines operator(). The
advantages of using a function object should become apparent soon.
Many of the algorithms in the Standard Template Library will accept a functor to
use instead of the default functor defined by the template class. This allows the
user of the algorithm to adapt the algorithm to their specific needs. You can use
the predefined function objects that are included with the STL, or you can roll your
own as long as your functors have the required function signatures.
There are 3 major types of function objects and several other less commonly used
function objects.
#include <iostream>
#include <iterator>
#include <vector>
#include <algorithm>
scores.push_back( 69 );
scores.push_back( 70 );
scores.push_back( 85 );
scores.push_back( 80 );
vector<int>::iterator new_end;
return 0;
}
The only problem with this example is that the failingGrade function is not very
flexible. It uses a hard-coded cutoff of 70.
Here is a better version that uses a function object (object of a class with an
operator() defined).
#include <iostream>
#include <iterator>
#include <vector>
#include <algorithm>
class Failing
{
private:
int cutoff;
public:
Failing( int below ) : cutoff(below) {}
bool operator()( int score )
{
return score < cutoff;
}
};
scores.push_back( 69 );
scores.push_back( 70 );
scores.push_back( 85 );
scores.push_back( 80 );
vector<int>::iterator new_end;
new_end = remove_if( scores.begin(), scores.end(), Failing(75) );
scores.erase( new_end, scores.end() );
return 0;
}
#include <iostream>
#include <iterator>
#include <vector>
#include <algorithm>
scores.push_back( 69 );
scores.push_back( 70 );
scores.push_back( 85 );
scores.push_back( 80 );
vector<int>::iterator new_end;
new_end = remove_if( scores.begin(), scores.end(), Failing<int>
(81) );
scores.erase( new_end, scores.end() );
return 0;
}
Predefined Function Objects
Since using function objects with algorithms is so common, a number of
predefined function objects are available for you to use in your code.
This is the concept of a Function Object Adapter. They can be used to convert
binary functors into unary functors or to do other conversions such as converting a
plain function into a function object or converting a class member function back
into a standard function so it can be used with the algorithms.