The Standard Library: Overview
Steven J. Zeil
std
”.
1 std/STL Containers
The key components of std
are
-
I/O library: e.g., streams
-
Utility ADTs: e.g., string
-
Containers (ADTs that hold one or more values of some other ADT): vector,set, …
-
Iterators: “positions” within a container
-
Algorithms: common programming “patterns”
You are already familiar with many parts of std
. You presumably were already familiar with the I/O portion. We have already looked at some utilities. Now we want to do a quick overview of the containers portion, prior to beginning to look at some of the specific containers in detail.
You may or may not have heard of the “STL” library before. When the C++ standards committee was considering what should be included in the standard library, std
, the early drafts included what we now recognize as the I/O and utility sections. A group of researchers from HP then proposed addition of their STL library to std
. STL consisted of a set of containers, iterators, and function templates (algorithms). “STL” stands for “Standard Template Library”, which may have been a bit presumptuous because it certainly was not part of the standard at the time. The C++ standards committee eventually accepted the STL, with some revisions, as part of std
.
2 The std Containers
We call an ADT a “container” if its main purpose is to provide a collection of items of some other, simpler type.
2.1 Sequential and Associative
Collections come in two flavors
- sequential
- values are accessed in an order determined by their insertion.
The
std
sequential containers are array, initializer_list, vector, deque, list, stack, queue, and priority queue. - associative
- allow “random” access
The
std
associative containers are set, map, multiset, multimap, unordered_set, unordered_map, unordered multiset, and unordered_multimap.The first four “ordered” containers are based on trees. The four “unordered” containers are based on hashing.
We’ll look at all of these in upcoming lessons.
2.2 Consistent Interfaces
One goal of the std
library is to provide consistent interfaces to many different containers.
-
Many operations are common to multiple ADTS.
-
These are always given the same name and formal parameter lists.
Examples:
-
If a container allows you to add and remove elements from its end, those operations are always called
push_back
andpop_back
.myContainer.pop_back (); // discard last element from container myContainer.push_back (x); // add x to end of container
Similarly, if a container allows you to add and remove elements from its front, those operations are always called
push_front
andpop_front
. -
Operations to add and remove elements at arbitrary positions are always called
insert
anderase
. These use iterators to specify the position:myContainer.insert (x, position); // insert x at the indicated // position, shifting other // elements out of the way myContainer.erase (position); // discard the element at that position myContainer.erase (start, stop); // discard all elements at positions // start up to (but not including) // stop.
-
You can test to see if a container is empty with
empty()
. You can ask how many items are in the container withsize()
.if (myContainer.empty()) { assert (myContainer.size() == 0); }
-
In the next reading, we will introduce the idea of an “iterator” to represent positions within the container. Nearly all containers will provide two iterator types, and these are called
iterator
andconst_iterator
. The beginning position in the container is given bybegin()
. The position just after the last element is given byend()
. When the container is empty,begin()==end()
. -
All containers will provide a set of data types describing their internal elements, e.g.:
template <typename T> class Some_Standard_Container { public: typedef T value_type; typedef value_type* pointer; typedef const value_type* const_pointer; typedef value_type& reference; typedef const value_type& const_reference; typedef std::size_t size_type; typedef ... iterator; typedef ... const_iterator;
value_type
is the data type of the elements stored within the container. For the containers that you might already be familiar with, vector and array, this seems pretty obvious.vector<int>::value_type
will beint
, andarray<Nonsense,100>::value_type
will beNonsense
. But when we get to the various forms of maps, you’ll see that thevalue_type
is not always obvious.As basic as it seems,
value_type
can be quite useful, especially when writing templates. For example, suppose that I wanted a function that would walk through two standard arrays, choosing the smaller value from each position, saving the results in another array:template <typename Array> Array collectSmallerElements (const Array& left, const Array& right) { Array result; for (int i = 0; i < left.size(); ++i) { typename Array::value_type x = left[i]; typename Array::value_type y = right[i]; result[i] = min(x,y); } return result; }
The
value_type
gives us a way to refer to the data types inside the containers, which would otherwise have been impossible to do.
-
pointer
,const_pointer
,reference
andconst_reference
are all variations on ways to get to avalue_type
element.-
What data types are actually used here depends on whether the underlying data structure could be broken by allowing the programmer to directly change element values “in place” within the container.
For example, with an array or vector, there’s no real problem with writing something like:
Container::reference element = container[22]; element.title = "Data Structures";
But some of the containers we will be looking at actually use the data values to determine where an element will be stored. So changing an element value might corrupt the entire container. Such containers will want to generate a compilation error if you try the code above. And they do that by providing different types for
reference
andpointer
:typedef T value_type; typedef const value_type* pointer; typedef const value_type* const_pointer; typedef const value_type& reference; typedef const value_type& const_reference;
because the compiler will not allow you to use const pointers and references to change the value of the data that they point to.
-
2.3 A Matter of Style
Because of this consistency in the interfaces, learning to use the std
containers is more a matter of learning the std
“style” than of learning 10-14 different ADT interfaces.
You can find a handy summary of the container interfaces in my STL containers reference sheets. You can also find some very good overviews and documentation from cplusplus.com.