Iterators in the C++ STL

Read this chapter, which covers iterators for groups of classes in contiguous memory.

The Standard Template Library (STL) provides a set of tools beyond those that are provided by the "base" C++ language. While a comprehensive discussion of the features of the STL is far beyond the scope of this text, there are several libraries that offer extremely important features with which you should become comfortable. Note: rather than assuming that using namespace std;  is at the top of every code example, each data type, function, or variable derived from the STL will be shown with the prefix std::. This highlights which parts of the examples below come from the STL, and which are part of the language.

23.1 #include <utility>#include <tuple> (C++11)

The pair class, found in <utility>, links two values which may be of different types. The tuple class, introduced in C++11, links any number of values which may be of different types. For example, to link a student’s identification number (an integer) and their grade point average (a float), we can write:

std:: pair <int, float> grades = { 112233 , 3.81 };

We can assign different values to the pair later with the make_pair function:

grades = std::make_pair(123450, 2.79);

The first and second members are used to extract the individual components of the pair: 

std:: cout << "ID:" <<grades.first << "(GPA"
  << grades.second << " ) " << std:: endl ;
// This prints:
// ID: 123450 (GPA 2.79)

If we wanted a more complicated set of values linked together, such as a student’s name, identification number, grade point average, and major, we could construct the following: 

tuple<std:: string, int, float, std:: string> ethan =
{"Ethan Allen", 802802, 3.15, "Engineering" };

Unfortunately, the tuple class does not have first or  second members. The first and second elements can be retrieved in a slightly more complicated way than with pair objects:

std:: cout << std:: get<0>(ethan) << " 's major is"
    <<std:: get<3>(ethan) << std::endl ;

// This prints:
// Ethan Allen's major is Engineering

In the code below, the get function returns a reference to the third element (the GPA) of the tuple ethan, and sets that value to 3.99:

std:: get<2>(ethan) = 3.99;

These types may not be all that useful by themselves, but are often used in conjunction with container classes like vector and map, described below.

23.2 #include <iterator>

Iterators are objects that refer to elements within a container object (like std::vectorstd::map, and std::array) and allow for traversal through those elements. The list of features in iterators vary depending on the container class. While the specifics of the iterators vary, most iterators belong to one of the following categories, based on the operations that may be performed on them.

23.2.1 Forward iterators

  • Can be incremented to move forward in the container to the next item
  • Can be dereferenced like a pointer variable
std:: array<int> myArray = { 5,10,15,20,25 };
std:: array:: iterator myIterator, arrayEnd;
arrayEnd = myArray.end() ;

//Demonstrating forward iteration
for (myIterator = myArray.begin() ;
    myIterator != arrayEnd;
    ++ myIterator )
  std:: cout << *myIterator << " " ;
std:: cout << std:: endl << "The end!" << std:: endl ;

// This prints:
// 5 10 15 20 25// The end!

23.2.2 Bidirectional iterators

  • Everything a forward iterator can do and:
  • Can be decremented to move backward in the container to the previous item
std:: array<int> myArray = { 5, 10, 15, 20, 25 };
std:: array:: iterator myIterator ,arrayBegin ;
arrayBegin = myArray.begin() ;

// Demonstrating backward iteration
for (myIterator = myArray.end() ;
    myIterator != arrayBegin ;
  std:: cout<< *myIterator << " ";
std:: cout << std:: endl << "The beginning!" << std:: endl;

// This prints:
// 25 20 15 10 5// The beginning!

23.2.3 Random access iterators

  • Everything a bidirectional iterator can do and:
  • Can use arithmetic operators to move forward and backward a certain number of items at once
  • Allows comparisons between iterators to determine relative positions in the container
  • Can use array-style access to elements in the container
// Create an array of 5 integers
std::array <int, 5> myArray = { 5, 10, 15, 20, 25 };
std::array <int, 5>::iterator myIterator, arrayEnd;
arrayEnd = myArray.end();
myIterator = myArray.begin();

// Demonstrating random access
std::cout << myIterator[1] << " "
    << myIterator[3] << std::endl;

// Demonstrating iterator comparisons
if( myIterator < arrayEnd )
    std::cout << "Not at the end of the array yet!"
        << std::endl;

// Demonstrating arithmetic operations on an iterator
for (myIterator = myArray.begin();
    myIterator != arrayEnd;
    myIterator += 2)
  std::cout << *myIterator << " ";
std::cout << std::endl << "The end!" << std::endl;

// This prints:
// 10 20
// Not at the end of the array yet!
// 5 15 25
// The end!

23.3 #include <vector>

Vectors are containers similar to arrays that are flexible in size and quite fast. While we can use iterators as above, we can also treat the vector much like an array.

// Start with 10 elements, all with the value 98.6
std::vector < float > temperatures( 10, 98.6 );

// The last element has a fever of 103.1 degrees!
temperatures[9]= 103.1;

for (int i = 0; i< temperatures.size(); i++ )
    std::cout << "Patient" << i << " 's temperature is"
        << temperatures[i] << std::endl;

The vector class also provides member functions front() and  back() which return references to the first element and the last element in the vector, respectively. For example: 

std::cout << "The last patient's temperature is"
    << temperatures.back() << std::endl;
std::cout << "The first patient's temperature is"
    << temperatures.front() << std::endl;

Don’t confuse the back() and front() functions with the end() and begin() functions. The  back() and front() functions return references to the elements, while end() and begin() return iterators pointing to those elements.

23.4 #include <map>

This library provides one of the STL’s associative container object classes. An associative container differs from an array in that items in an array are referenced with a number which indicates the item’s position in memory:

int myArray[10]; // An array of ten integers
myArray[0] = 5; // Set the first integer in the array to −5

An associative container, on the other hand, can use any data type to reference the items in the container. For example, you might choose to use a string to reference a collection of int items to store a list of students’ ages according to their names.

std :: map<std :: string, int > students; 

Perhaps you want to create the object with some initial values:

std :: map<std :: string, int> students =
    {  { "John", 19},
       { "Max", 19},
       { "Christine", 20},
       { "Maria", 18}  };

This code produces a structure like in Figure 23.1. With these names and ages paired, we can now retrieve the ages using the names.

string name = "Christine" ;
std::cout << name << " is " << students[name]
    << " years old." << std::endl;

// This code prints:
// Christine is 20 years old.

New students may also be added in the following way:

students[ "June" ] = 18;
students[ "Omar" ] = 19;

Objects of type map may be iterated, and in C++11, their contents can be printed in a range-based for loop as we briefly demonstrate here. Each item in the std::map<std::string, int> is of type std::pair<std::string,int>.

for (auto& item : students)
    std::cout << item.first << " is " << item.second << 
        years old." << std::endl;

// This code prints:
// John is 19 years old
// Max is 19 years old
// Christine is 20 years old
// Maria is 18 years old
// June is 18 years old
// Omar is 19 years old

Source: Jeremy A. Hansen,
Creative Commons License This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 License.

Last modified: Thursday, May 20, 2021, 2:15 PM