bugl
bugl
HomeLearnPatternsPathsSearch
HomeLearnPatternsPathsSearch

Loading lesson path

Learn/C++/C++ Data Structures
C++•C++ Data Structures

C++ Iterator

Flash cards

Review the key moves

1/4
Core idea

What is the main idea behind C++ Iterator?

Lesson checks

Practice each idea before moving on

Short Mimo-style checks built from this lesson's code, terms, and sequence.

1Quick choice

Which statement best captures the main point of this lesson?

2Fill blank

Complete the missing token from the example code.

// ___ a vector called cars that will store strings vector<string> cars = {"Volvo", "BMW", "Ford", "Mazda"}; // Create a vector iterator called it vector<string>::iterator it; // Loop through the vector with the iterator
3Order

Put the learning moves in the order that makes the concept easiest to apply.

Iterate Through other Data Structures
Iterate in Reverse
For-Each Loop vs. Iterators

C++ Iterators

Iterators are used to access and iterate through elements of data structures ( vectors , sets , etc.), by " pointing " to them.

It is called an "iterator" because "iterating" is the technical term for looping .

To iterate through a vector, look at the following example:

Example

// Create a vector called cars that will store strings vector<string> cars = {"Volvo", "BMW", "Ford", "Mazda"}; // Create a vector iterator called it vector<string>::iterator it; // Loop through the vector with the iterator
for (it = cars.begin(); it != cars.end(); ++it) {
  cout << *it << "\n";
}
  • First we create a vector of strings to store the names of different car manufactures.
  • Then we create a "vector iterator" called it , that we will use to loop through the vector.
  • Next, we use a for loop to loop through the vector with the iterator. The iterator ( it ) points to the first element in the vector ( cars.begin() ) and the loop continues as long as it is not equal to cars.end() .
  • The increment operator ( ++it ) moves the iterator to the next element in the vector.
  • The dereference operator ( *it ) accesses the element the iterator points to.

Note

The type of the iterator must match the type of the data structure it should iterate through ( string in our example)

What is begin() and end() ?

begin() and end() are functions that belong to data structures , such as vectors and lists . They do not belong to the iterator itself. Instead, they are used with iterators to access and iterate through the elements of these data structures.

  • begin() returns an iterator that points to the first element of the data structure.
  • end() returns an iterator that points to one position after the last element.

To understand how they work, let's continue to use vectors as an example:

vector<string> cars = {"Volvo", "BMW", "Ford", "Mazda"};
vector<string>::iterator it;

End Example

end() points to one position after the last element in the vector (meaning it doesn't point to an actual element, but rather indicates that this is the end of the vector).

So, to use end() to point to the last element in the cars vector (Mazda), you can use cars.end() - 1 :

// Point to the last element it = cars.end() - 1;

Why do we say "point"?

Iterators are like " pointers " in that they "point" to elements in a data structure rather than returning values from them. They refer to a specific position, providing a way to access and modify the value when needed, without making a copy of it. For example:

// Point to the first element in the vector it = cars.begin(); // Modify the value of the first element *it = "Tesla"; // Volvo is now Tesla

The auto Keyword

In C++ 11 and later versions, you can use the auto keyword instead of explicitly declaring and specifying the type of the iterator.

The auto keyword allows the compiler to automatically determine the correct data type, which simplifies the code and makes it more readable:

Instead of this

vector<string>::iterator it = cars.begin();
auto it = cars.begin();

In the example above, the compiler knows the type of it based on the return type of cars.begin() , which is vector<string>::iterator .

The auto keyword works in for loops as well:

Runnable example

for (auto it = cars.begin(); it != cars.end(); ++it) {
  cout << *it
  << "\n";
}

For-Each Loop vs. Iterators

You can use a for-each loop to just loop through elements of a data structure, like this:

Example

// Create a vector called cars that will store strings vector<string> cars = {"Volvo", "BMW", "Ford", "Mazda"}; // Print vector elements
for (string car : cars) {
  cout << car << "\n";
}

When you are just reading the elements, and don't need to modify them, the for-each loop is much simpler and cleaner than iterators.

However, when you need to add, modify, or remove elements during iteration , iterate in reverse, or skip elements, you should use iterators:

Example

// Create a vector called cars that will store strings vector<string> cars = {"Volvo", "BMW", "Ford", "Mazda"}; // Loop through vector elements
for (auto it = cars.begin(); it != cars.end(); ) {
  if (*it == "BMW") {
    it = cars.erase(it); // Remove the BMW element
  } else {
  ++it;
}
}
// Print vector elements
for (const
string& car : cars) {
  cout << car << "\n";
}

Iterate in Reverse

To iterate in reverse order, you can use rbegin() and rend() instead of begin() and end() :

Example

// Iterate in reverse order
for (auto it = cars.rbegin(); it != cars.rend(); ++it) {
  cout << *it << "\n";
}

Iterate Through other Data Structures

Iterators are great for code reusability since you can use the same syntax for iterating through vectors, lists, deques, sets and maps:

List Example

// Create a list called cars that will store strings list<string> cars = {"Volvo", "BMW", "Ford", "Mazda"}; // Loop through the list with an iterator
for (auto it = cars.begin(); it != cars.end(); ++it) {
  cout << *it << "\n";
}

Deque Example

// Create a deque called cars that will store strings deque<string> cars = {"Volvo", "BMW", "Ford", "Mazda"}; // Loop through the deque with an iterator
for (auto it = cars.begin(); it != cars.end(); ++it) {
  cout << *it << "\n";
}

Set Example

// Create a set called cars that will store strings set<string> cars = {"Volvo", "BMW", "Ford", "Mazda"}; // Loop through the set with an iterator
for (auto it = cars.begin(); it != cars.end(); ++it) {
  cout << *it << "\n";
}

Map Example

// Create a map that will store strings and integers map<string, int> people = { {"John", 32}, {"Adele", 45}, {"Bo", 29} }; // Loop through the map with an iterator
for (auto it = people.begin(); it != people.end();
++it) {
  cout << it->first << " is: " << it->second << "\n";
}

The examples above shows how to iterate through different data structures that support iterators ( vector , list , deque , map and set support iterators, while stacks and queues do not ).

Algorithms

Another important feature of iterators is that they are used with different algorithm functions, such as sort() and find() (found in the <algorithm> library), to sort and search for elements in a data structure.

For example, the sort() function takes iterators (typically returned by begin() and end() ) as parameters to sort elements in a data structure from the beginning to the end.

In this example, the elements are sorted alphabetically since they are strings:

Example

#include <iostream>
#include <vector>
#include <algorithm>
// Include the <algorithm> library using namespace std; int main() { // Create a vector called cars that will store strings vector<string> cars = {"Volvo", "BMW", "Ford", "Mazda"}; // Sort cars in alphabetical order sort(cars.begin(), cars.end()); // Print cars in alphabetical order
for (string car : cars) {
  cout << car << "\n";
}
return 0;
}

And in this example, the elements are sorted numerically since they are integers:

Example

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main() {
  // Create a vector called numbers that will store integers vector<int> numbers = {1, 7, 3, 5, 9, 2}; // Sort numbers numerically sort(numbers.begin(), numbers.end());
  for (int num : numbers) {
    cout << num << "\n";
  }
return 0;
}

To reverse the order, you can use rbegin() and rend() instead of begin() and end() :

Example

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main() {
  // Create a vector called numbers that will store integers vector<int> numbers = {1, 7, 3, 5, 9, 2}; // Sort numbers numerically in reverse order sort(numbers .rbegin() , numbers .rend() );
  for (int num : numbers) {
    cout << num << "\n";
  }
return 0;
}

Previous

C++ Maps

Next

C++ Algorithm