An iterator in C++ is a pointer-like object that points to an element of the STL container. They are generally used to loop through the contents of the STL container in C++. The main advantage of STL iterators is that they make the STL algorithms independent of the type of container used. We can just pass the iterator to the container elements instead of the container itself to the STL algorithms.
In this article, we will learn about iterators in C++, their types, and how to use them.
Iterator Declaration
Each container in C++ STL has its own iterator. So, we have to declare an iterator as:
<type>::iterator it;
where,
- type: Type of container for which the iterator is declared.
- it: Name assigned to iterator object.
We can then initialize it by assigning some valid iterator. If we already have an iterator to be assigned at the time of delcaration, then we can skip the type declaration using the auto keyword.
auto it = iter
where, iter is the iterator assigned to the newly created it iterator.
Our C++ Course covers the use of iterators in the STL, ensuring you understand how to traverse different container types.
Example of Iterators
The below program illustrates how to use the iterator to traverse the vector container:
C++
// C++ program to show how to use iterator to
// traverse vector container
#include <bits/stdc++.h>
using namespace std;
int main() {
vector<int> arr = {1, 2, 3, 4, 5};
// Defining an iterator pointing to
// the beginning of the vector
vector<int>::iterator first =
arr.begin();
// Defining an iterator pointing to the
// end of the vector
vector<int>::iterator last =
arr.end();
// Iterating the whole vector
while(first != last) {
cout << *first << " ";
first++;
}
return 0;
}
As you may have noticed, we have used vector::begin() and vector::end() function. These functions are the member functions to std::vector that returns the iterator to the first and one element after the last element of the vector. We use the iterators return be these functions to iterate the vectors.
Container Iterator Functions
C++ STL provides some member functions in STL container that return the iterators to at least the first and the last element. These member methods are defined in almost all of the STL container (leaving some limited access containers like stack, queue) with the same name for consistency.
The following table lists all methods that returns the iterator to the containers:
Iterator Function
| Return Value
|
---|
begin()
| Returns an iterator to the beginning of container.
|
end()
| Returns an iterator to the theoretical element just after the last element of the container.
|
cbegin()
| Returns a constant iterator to the beginning of container. A constant iterator cannot modify the value of the element it is pointing to.
|
cend()
| Returns a constant iterator to the theoretical element just after the last element of the container.
|
rbegin()
| Returns a reverse iterator to the beginning of container.
|
rend()
| Returns a reverse iterator to the theoretical element just after the last element of the container.
|
crbegin()
| Returns a constant reverse iterator to the beginning of container.
|
crend()
| Returns a constant reverse iterator to the theoretical element just after the last element of the container.
|
For Example, if vec is the name of the vector, then we can use the above methods as shown below:
vec.begin(), vec.rbegin(), vec.cbegin(), vec.crbegin()
vec.end(), vec.rend(), vec.cend(), vec.crend()
Iterators Operations
Just like pointer arithmetic, there are some operations that are allowed on C++ iterators. They are used to provide different functionalities that increases the importance of iterators. There are 5 valid iterator operations in C++:
- Dereferencing Iterators
- Incrementing/Decrementing Iterators
- Adding/Subtracting Integer to Iterators
- Subtracting Another Iterator
- Comparing Iterators
Dereferencing Iterators
Dereferencing operation allows the users to access or update the value of the element pointed by the iterator. We use the (*) indirection operator to dereference iterators just like pointers.
Syntax
*it; // Access
*it = new_val; // Update
where new_val is the new value assigned to the element pointed by iterator it.
Incrementing/Decrementing Iterators
We can increment or decrement the iterator by 1 using (++) or (–) operators respectively. Increment operation moves the iterator to the next element in the container while the decrement operation moves the iterator to the previous element.
Syntax
it++; // post-increment
++it; // pre-increment
it–; // post-decrement
—it; // pre-decrement
Adding/Subtracting Integer to Iterators
We can also add or subtract an integer value from the iterators. It will more the iterator next or previous position according to the added integer value.
Syntax
it + int_val; // Addition
it – int_val; // Subtraction
where int_val is the integer values that is being added or subtracted from the iterator it.
Subtracting Another Iterator
We can subtract one iterator from another to find the distance (or the number of elements) between the memory they are pointing to.
Syntax
it1 – it2
Comparing Iterators
We can also test the two iterators of the same type against each other to find the relationship between them. We can use the relational operators like (==) equality and (!=) inequality operators along with other relational operators such as <, >, <=, >=.
Syntax
it1 != it2 // Equal to
it1 == it2 // Not equal to
it1 > it2 // Greater than
it1 < it2 // Less than
it1 >= it2 // Greater than equal to
it1 <= it2 // Less than equal to
Types of Iterators in C++
STL iterators can be divided on the basis of the operations that can be performed on them. As such. there are 5 main types of iterators in C++ which as listed in the below table along with supported containers and supported iterator operations.
Iterator
| Description
| Supported Containers
| Supported Operations
|
---|
Input Iterator
| It is a one-way iterator used to read the values.
| Input Stream
| Dereferencing, Increment, Equality
|
---|
Output Iterator
| It is also a one-way iterator but used to assign the values. It cannot access the values.
| Output Stream
| Dereferencing (write only), Increment
|
---|
Forward Iterators
| It can access and as well as assign the values. It is the combination of both input and output iterator.
| forward_list, unordered_map, unordered_set
| Dereferencing, Increment, Equality
|
---|
Bidirectional Iterators
| It can move in both direction either in forward or backward. The containers like list, set, and multimap supports bidirectional iterators.
| list, map, set, multimap, multiset
| Dereferencing, Increment/Decrement, Equality
|
---|
Random Access Iterators
| Random-access iterators are iterators that can be used to access elements at distance from the element they point to, offering the same functionality as pointers.
| vector, deque, array, string
| All
|
---|
As we may have noticed from the above table, apart from the input and output iterators, as we go down the table, the iterator type contains the features of above iterator along with some new features.
Iterator Adaptors
Iterator adaptors in C++ are the special type of iterators that are built over traditional iterators to provide specialized functionality. There are many iterator adaptors in C++ some of which are given below:
Iterator Adaptors Type
| Description
|
---|
Reverse Iterator
| The reverse iterator is built over bidirectional or above type of operator and allows users to traverse the container in the reverse direction.
|
Stream Iterators
| The stream iterators namely, istream and ostream iterators are built on the input and output iterators respectively. These iterators allow the users to use the streams as containers.
|
Move Iterators
| Move iterators are used to introduce the move semantics in STL algorithms. The move iterators move the ownership of the copied container data to the copying container without creating the extra copies.
|
Inserter Iterator
| The insertor iterators allows you to insert the given elements at some position in the container. There are three insertor iterators in C++:
- back_insert_iterator: Inserts at the back of the container.
- front_insert_iterator: Inserts at the front of the container.
- insert_iterator: Inserts at anywhere in the container.
These iterators can be created using back_inserter(), front_inserter(), inserter() functions in C++.
|
Iterator Utility Functions in C++
C++ STL provide the various function to simplify the working with iterators. They are listed in the below table:
Function | Description | Syntax |
---|
std::advance | Advances an iterator by a specific number of positions. | advance(it, n) |
---|
std::next | Returns the iterator that is a specified number of positions ahead of the given iterator. | next(it, n) |
---|
std::prev | Returns the iterator that is a specified number of positions behind the given iterator. | prev(it, n) |
---|
std::distance | Returns the number of elements between two iterators. | distance(it1, it2) |
---|
std::begin | Returns an iterator to the first element of the given container. | begin(container) |
---|
std::end | Returns an iterator to the element following the last element of the given container. | end(container) |
---|
std::rbegin | Returns a reverse iterator to the last element of the given container. | rbegin(container) |
---|
std::rend | Returns a reverse iterator to the element preceding the first element of the given container. | rend(container) |
---|
std::inserter | Creates an insert iterator that inserts elements into a container at a specified position. | inserter(container, position) |
---|
std::back_inserter | Creates a back insert iterator that appends elements to the end of a container. | back_inserter(container) |
---|
std::front_inserter | Creates a front insert iterator that inserts elements at the front of a container. | front_inserter(container) |
---|
Applications of Iterators with Examples
Iterators are extensively used in C++ for many different purposes while working with STL containers and algorithms. Following are some primary applications of iterators in C++ which their code examples:
Traversing Containers
Traversing STL containers is the most basic application of iterators. In this, we use the begin() and end() functions to get the begin and end iterators to traverse the whole container. Basically, we keep incrementing the begin iterator till it is not equal to the end.
Example
C++
// C++ program to show how to use iterator to
// traverse set container
#include <bits/stdc++.h>
using namespace std;
int main() {
set<int> s = {10, 20, 30, 40, 50};
// Iterator to the beginning of the set
auto it = s.begin();
// Iterating through the entire set
while (it != s.end()) {
// Dereferencing iterator to access value
cout << *it << " ";
// Incrementing the iterator
it++;
}
return 0;
}
Just like that, any container can be traversed.
Reversing a Container
Reverse iterators allow you to traverse a container from the end to the beginning without needing to manually handling the reversal.
Example
C++
// C++ program to show how to use reverse iterators
// to traverse a container from end to beginning
#include <bits/stdc++.h>
using namespace std;
int main() {
vector<int> vec = {10, 20, 30, 40, 50};
// Defining reverse iterators pointing to the
// reverse beginning of vec
auto it = vec.rbegin();
// Iterating the whole vector in reverse
while (it != vec.rend()) {
cout << *it << " ";
it++;
}
return 0;
}
Container-Independent Algorithms
Iterators allow algorithms to work with any container type, making functions like std::sort(), std::find(), and std::for_each() more flexible. You can pass iterators instead of the actual container.
Example
C++
// C++ program to show how algorithms can work
// with iterators of any container type
#include <bits/stdc++.h>
using namespace std;
int main() {
vector<int> vec = {30, 10, 40, 10, 50};
multiset<int> ms = {10, 30, 10, 20, 40, 10};
// Using the std::count() algorithm to count
// the number of occurences of 10 in vector
// and multiset using iterator
cout << "10s in Vector: " << count(vec.begin(),
vec.end(), 10) << endl;
cout << "10s in Multiset: " << count(ms.begin(),
ms.end(), 10);
return 0;
}
Output10s in Vector: 2
10s in Multiset: 3
Additional Applications of Iterators
There are more applications of STL iterators:
- Distance Calculation: Using std::distance(), iterators help calculate the number of elements between two positions in a container.
- Stream Iteration: Stream iterators allow you to treat input/output streams like containers, making it easier to read from and write to streams using STL algorithms.
- Move Semantics in STL Algorithms: Move iterators introduces the move semantics in STL algorithms which helps in increasing performance and efficiency by avoiding unnecessary copying. The data will be moved according to the rules of move semantics.
- Custom Iterators for Data Structures: Custom iterators can be implemented for non-STL data structures like trees or graphs to provide the support for STL algorithms and many other features. We may need to follow a few set of rules and conventions to provide proper incrementing, decrementing, and other operations.
Iterators in C++ STL – FAQs
What is the difference between iterators and pointers in C++?
Iterators works similarly to pointers but provide a more generalized way to access elements in a container. Unlike raw pointers, iterators are designed to work with a wide variety of data structures (e.g., vectors, lists) and provide additional operations, such as the ability to traverse and manipulate containers in specific ways (forward, reverse, or bidirectionally).
Why does C++ have both cbegin() and begin()?
cbegin() returns a constant iterator, ensuring that the container’s elements cannot be modified during iteration. This is useful when you need to ensure read-only access.
Why do we need the std::advance() function?
std::advance() abstracts the logic for advancing an iterator by a specific number of steps. This is especially helpful for iterator types that do not support random access, like bidirectional iterators where we have to manually increment the iterator given number of times.
Why use iterator adaptors like back_inserter()?
Iterator adaptors, such as back_inserter(), allow for specialized functionality, like appending elements to a container without manually managing the container’s size or position.