13.7. Using iterators

Assigning an iterator explicitly to a variable works much like any other type:

vector<int> nums = {1, 2, 3, 4, 5};
vector<int>::iterator it = nums.begin();

The variable it now points to the beginning of the container nums and can used much like a pointer:

vector<int> nums = {1, 2, 3, 4, 5};
vector<int>::iterator it = nums.begin();

cout << *it;  // prints: 1

The iterator type always matches the value type of the enclosing container. Just as with pointers, an iterator to a vector<int> is a different type from an iterator to a vector<string>.

It is possible to declare an iterator and use it in a traditional for loop:

vector<int> nums = {1, 2, 3, 4, 5};
cout << "nums contains:";

for (vector<int>::iterator it = nums.begin();
     it != nums.end(); ++it) {
    std::cout << ' ' << *it;
}

Which produces:

nums contains: 1 2 3 4 5

A while loop can produce equivalent results:

vector<int> nums = {1, 2, 3, 4, 5};
cout << "nums contains:";

vector<int>::iterator it = nums.begin();
while (it != nums.end())
    std::cout << ' ' << *it;
    ++it;
}

We can shorten either example with auto, since the compiler can easily determine what type is returned from begin():

for (auto it = nums.begin(); it != nums.end(); ++it) {
    std::cout << ' ' << *it;
}

Example code like one of the two previous examples is commonly found on the web, even when the point of the example has nothing to do with iterators. When you don’t need an iterator, don’t use it:

for (const auto& n: nums) {
    std::cout << ' ' << n;
}

A common source of error for new programmers is confusion about the types used in these two loops:

begin()

Always returns an iterator that must be dereferenced in order to access the element value.

The range for declaration

Always is assigned a value from the container. Unless the container is a container of pointers, no dereferencing is needed.

13.7.1. Limits of Range-based for loops

The range-for loop, while convenient, has limitations.

Any situation in which you do not need or want to visit every element requires a traditional loop:

for (int i=n; i>0; i/=2) {
  // do something with i . . .
}

Similarly, if you need to iterate through multiple containers in a single loop, possibly at different rates, then you need a traditional for loop:

for (int i=n, j=0; i>0; i/=2, j++) {
  // do something with i and j . . .
}

If you need to traverse a container and remove items, then you need an explicit iterator so that you can call the container erase method.

See the erase example in the following section.

13.7.2. Container functions that require iterators

Most container functions that use position information do not accept an integral position or an index like operator[]. Position information is expressed using iterators.

insert

Inserts elements at the specified location in the container.

Create a vector<int> and initialize it with 3 values:

std::vector<int> nums(3,100);

Insert a value at the beginning of the vector:

auto it = nums.begin();
it = nums.insert(it, 200);

Insert 2 values at the beginning of the vector:

it = nums.insert(it, 2, 200);

Insert one vector into another vector:

auto it = nums.begin();
std::vector<int> fib {1, 1, 2, 3, 5, 8, 13, 21};
nums.insert(it+2, fib.begin(), fib.end());
erase

Removes specified elements from the container. erase may remove a single element or a contiguous range of elements.

Given a vector<int>:

std::vector<int> nums = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};

We can erase the first element:

nums.erase(nums.begin());

or erase a range of adjacent elements:

nums.erase(nums.begin()+2, nums.begin()+5);

or erase other elements:

// Erase all even numbers 
for (auto it = nums.begin(); it != nums.end(); ) {
  if (*it % 2 == 0) {
    it = nums.erase(it);
  } else {
    ++it;
  }
}

Things to note about the last erase example:

  • it is not incremented in the for loop iteration expression

  • If an element is erased, the current iterator is invalidated. Any further use would be an error in a vector.

    The vector::erase function returns the iterator to the next element in the container.

  • If an element is not erased, then increment the iterator.


You have attempted of activities on this page