C++ Iterators
What are iterators ?
Iterators are among the four foundations of the C++ Standard Template Library, also known as the STL. The memory address of the STL container classes is pointed to using an iterator. To some extent, you can link them along a pointer for better comprehension.
Iterators serve as a link between algorithms and STL containers, allowing the data inside the container to be modified. They let you to iterate through the container, access and assign values, and apply various operators to them in order to get the required outcome.
Unlike pointers, iterators are separated into categories, and each one may be utilized in any algorithm which fits into that category. Iterators give access such that containers would not need to know about algorithms, and algorithms need not know about containers. The ideal world model that the human mind desires is one where nobody knows anything and everything occurs just as it should.
Important briefing :
- Iterators are used to go from one element to the next, which is referred as iterating through the container.
- An iterator's key benefit is that it defines a shared interface for all container types.
- Iterators allow the method to be independent of the container type.
- Iterators give a common way to browse across a container's components.
Uses of Iterators in C++ :
In C++, an iterator is used for the following purposes :
- An iterator's primary goal is to get access to the STL container elements and conduct actions on them.
- Because the iterators enable shared usage for all of them, the underlying structure of a container is irrelevant.
- The container type has no bearing on iterator algorithms.
- It is possible to loop over container elements using an iterator. It can also provide such elements access to change their values.
- For STL container classes, iterators use a generic approach. This eliminates the need for programmers to learn about various iterators for various containers.
Syntax :
<ContainersType> :: iterator;
<ContainersType> :: consts_iterator;
Here, ContainersType specifies the kind of container for whom the iterator is defined.
The Iterators were subjected to the following operations :
- The '*' operator gives the member of the iterator's current position.
- The iterator is incremented by one with the ++ operator. As a result, an iterator leads to the container's next element.
- : Both the operator (==) and the operator (!=) evaluate if the 2 iterators refer to the same spot or not.
- The iterator is assigned using the '=' operator.
Iterators vs. Pointers : What's the Difference ?
Even though the pointers and iterators appear to be the same at first look, there are many key distinctions to be aware of.
Pointers :
Pointers are variables that store the memory address of the variable to which they point. A pointer, like any other variable, has a data type that matches the type of variable whose memory it is holding. The pointer assists in sending huge amounts of data to functions by simply supplying the object's memory location.
Syntax for declaring a pointer :
datatype* pointers_name
Example :
#include <iostream>
using namespace std;
int main()
{
// initializing the variable myVrbl
int myVrbl = 100;
// initializing the pointer pntr
// pointing to the variable myVrbl
int* pntr = &myVrbl;
// printing the variable myVrbl will show 100
cout << "Value that is stored in myVrbl: " << myVrbl;
cout << "\n";
// printing the *pntr will also show 100
cout << "Dereferenced pointer that points to myVrbl : " << *pntr;
cout << "\n";
// updating the value of the variable myVrbl
myVrbl++;
// now the *pntr will print 101, since variablr myVrbl has been updated
cout << "Dereferenced pointer that points to myVrbl after updating myVrbl : ";
cout << *pntr;
cout << "\n\n";
return 0;
}
Output :
Value that is stored in myVrbl : 100
Dereferenced pointer that points to myVrbl : 100
Dereferenced pointer that points to myVrbl after updating myVrbl : 101
Explanation :
In the above example, we showed the use of pointers in C++. We first initialized the variable myVrbl and allotted a value to it. Then the pointer pntr was initialized and that was set to point towards the variable myVrbl. We then printed the variable myVrbl and then pointer pntr and both showed the exact same output. Then we incremented the value of the pntr only and printed it and got the incremented value as expected.
Iterators :
Iterators are often utilized to refer to the STL containers' memory locations. In addition, an iterator is utilized to loop across the data structures. It can access and assign values in ways that a pointer cannot.
In C++, pointers could also point to functions, but iterators are only used to execute actions on STL containers.
Syntax for declaring a iterator :
type_container :: iterator itrtr_name
Example :
#include <iostream>
#include <vector>
using namespace std;
int main()
{
// initializing the vector vect1
vector<int> vect1 = { 100, 200, 300, 400 };
// declarint the iterator itrtr
vector<int>::iterator itrtr;
// accessing the vector elements without the iterator
cout << "Traversing without the iterator : ";
for (int x = 0; x < 4; ++x) {
cout << vect1[x] << " ";
}
cout << "\n";
// accessing the vector elements using the iterator
cout << "Traversing using the iterator : ";
for (itrtr = vect1.begin(); itrtr != vect1.end(); ++itrtr) {
cout << *itrtr << " ";
}
cout << "\n\n";
// inserting an element into vect1 vector
vect1.push_back(500);
// accessing the vector elements without the iterator
cout << "Traversing without the iterator : ";
for (int x = 0; x < 5; ++x) {
cout << vect1[x] << " ";
}
cout << "\n";
// accessing the vector elements using the iterator
cout << "Traversing using the iterator ";
for (itrtr = vect1.begin(); itrtr != vect1.end(); ++itrtr) {
cout << *itrtr << " ";
}
cout << "\n\n";
return 0;
}
Output :
Traversing without the iterator : 100 200 300 400
Traversing using the iterator : 100 200 300 400
Traversing without the iterator : 100 200 300 400 500
Traversing using the iterator : 100 200 300 400 500
Explanation :
In the above example, we showed the use of iterators in C++. We first initialized a vector called vect1 with values given. Then we initialized an iterator called itrtr. We first accessed the vector elements without the iterator and printed the result it gave using a for loop. Then we accessed the vector elements using the iterator and with the help of for loop we printed the required output. Then we repeated the process by adding one more vector element and accessed all the elements again with and without iterator and printed them using the for loop to get the desired output.
Various Categories of the iterators :
As previously stated, there are five different categories of iterators in the C++ STL. Here, we will go through each of the five iterators in short. They constitute a class hierarchy, with each category inheriting the permitted operations from the one before it. Like the bi-directional iterators, which may travel forward and backward gradually over the variety of elements in the container to which they have been tied.

Fig. Types of Iterators
The following are the five categories of iterators :
1. Input iterators :
Among the five primary iterators in C++, the input iterator is the easiest and least utilized. This iterator is used consecutively for input operations. To put it another way, it is utilized to retrieve the values from container. It's a one-directional iterator. You are only permitted to increase the iterator after reading a value. You can’t decrease the input iterator in just about any way.
For an input iterator, the following operators are used:
2. Output iterators :
The output iterators do the exact opposite of the input iterators. For output operations, this iterator is utilized consecutively. In other words, it is employed in the assignment of values. However, it is unable to access the values. It is a companion to the input iterators, which allow you to access but not assign values. It is a one-directional iterator, just as the input iterator. You can only increase the iterator once you've assigned a value, and you can't decrease the output iterator in any manner.
The following operators are used in an output iterator :
3. Forward iterators :
Both of the input and output iterators are served by forward iterators. As a result, these iterators are called input-output operators. The values may be accessed (input iterator’s functionality) as well as assigned (functionality of output iterators). In one-way iterators, as their name implies, only forward movement is allowed. Additionally, Bidirectional and Random access iterators are valid forward iterators.
Forward iterators employ the following operators:
4. Bidirectional Iterators :
Iterators that are bidirectional and can iterate in any of the two directions. They are referred to as forward iterators with two increment operators because they perform the same functions as forward iterators but may travel in both directions. Bidirectional iterators are supported by containers like list, set, and multimap. Iterators with random access are also valid bidirectional iterators.
A bidirectional iterator uses the following operators:
5. Random Access Iterators :
The most powerful iterators are random-access iterators. They are not constrained to moving in a sequential manner; as their name implies, they can access any element within the container at any time. They're the ones with the same functionality as pointers. Random access iterators may be used to implement any relational operator. We may use relational operators on Random Access iterators instead of bidirectional operators.
STL Containers and iterators :
All five types of iterators are not supported by all STL containers. For example, the container "vector" supports random-access iterators, but the container "list" supports bidirectional iterators.
STL containers and the iterators that they support in C++ are listed in the table below:

Fig. Containers and Iterators Supported
Functions of Iterators :
1. begin():
The begin() method returns a reference to the container's initial element. This pointer is bidirectional since it can point in any direction of the container.
Syntax :
begin()
2. end() :
The end() function returns a reference to the element which appears after the container's last element. This element is a virtual element which holds the address of the previous element.
Syntax :
end()
Example :
#include <iostream>
#include<iterator>
#include<vector>
using namespace std;
int main()
{
std::vector<int> vect{10,20,30,40,50};
vector<int>::iterator itrtr;
for(itrtr=vect.begin();itrtr!=vect.end();itrtr++)
{
std::cout << *itrtr <<" ";
}
return 0;
}
Output :
10 20 30 40 50
Explanation :
In the above example, we first defined a vector called vect with five elements. Then we used the begin() method to return a reference to the container's initial element. We used the end() function to return a reference to the element which appears after the container's last element. We applied them using a for loop and printed all the vector vect elements as the required output.
3. advance() :
The advance() function moves the iterator forward from its current location. It accepts an integer as a parameter. The advance() function advances the pointer to the specified integer position.
Syntax :
advance(iterator itrtr ,int dist)iterator itrtr ,int dist)
Example :
#include<iostream>
#include<iterator>
#include<vector>
using namespace std;
int main()
{
// initializing the vector myVctr
vector<int> myVctr = { 10, 20, 30, 40, 50 };
// declaring the iterator itrtr
vector<int>::iterator itrtr;
// initializing iterator
itrtr = myVctr.begin();
// printing the original value onto
// which the iterator itrtr is pointing
cout << "The iterator is originally pointing towards : ";
cout << *itrtr << " ";
cout << "\n\n";
// updating the iterator by increasing it
// by a dist of 3 using the advance() function of iterator
advance(itrtr,3); // iterator will now point towards 40
// printing the current value to which iterator is pointing currently
cout << "The iterator is now pointing towards : ";
cout << *itrtr << " ";
cout << "\n\n";
return 0;
}
Output :
The iterator is originally pointing towards : 10
The iterator is now pointing towards : 40
Explanation :
In the above example, we demonstrated the use of advance() function with the iterators in C++. We first initialized a vector called myVctr with five elements. Then we declared an iterator called itrtr and initialized it using the begin() function with the iterator. Then we printed the original value towards which the iterator was pointing to. The advance() function was then used to update the iterator and it was incremented by a distance of three to now point towards the third next element from the original value. The updated value, towards which the iterator itrtr was pointing to now, was printed as the required output.
4. next() :
The next() function returns an iterator pointing to the element obtained by increasing the iterator pointer first from current element.
Syntax :
next (iterator itrtr ,int x)
5. prev() :
The next() function is the polar opposite of the prev() method. It produces an iterator pointer that refers to the element obtained by subtracting the current element from the iterator.
Syntax :
previous(iterator itrtr, int x)
Example :
#include<iostream>
#include<iterator>
#include<vector>
using namespace std;
int main()
{
// initializing the vector myVctr
vector<int> myVctr = { 10, 20, 30, 40, 50 };
// declaring the iterators for the vector myVctr
vector<int>::iterator itrtr1 = myVctr.begin();
vector<int>::iterator itrtr2 = myVctr.end();
// storing the pointer returned by the next() function
// after increasing the itrtr1 by 3
auto nextPntr = next(itrtr1, 3);
// storing the pointer returned by the prev() function
// after decreasing the itrtr2 by 3
auto prevPntr = prev(itrtr2, 3);
// Displaying the iterator’s position
// printing the value of new iterator that is returned by the next() function
cout << "The new pointer after the use of next() now points towards : ";
cout << "\n";
cout << *nextPntr << " ";
cout << "\n\n";
// Displaying the iterator’s position
// printing the value of the new iterator that is returned by the prev() function
cout << "The new pointer after the use of prev() now points towards : ";
cout << "\n";
cout << *prevPntr << " ";
cout << "\n\n";
return 0;
}
Output :
The new pointer after the use of next() now points towards : 40
The new pointer after the use of prev() now points towards : 30
Explanation :
In the above example, we demonstrated the use of the next() and the prev() function in our code. We initialized a vector called myVctr with five elements. Then we declared the iterators itrtr1 and itrtr2 for the vector myVctr using the begin() and end() function respectively. In the pointer nextPntr, the pointer returned by the next() function after increasing the itrtr1 by distance three, was stored. In the pointer prevPntr, the pointer returned by the prev() function after decreasing the itrtr2 by distance three, was stored. Then we printed the value of new iterator which was returned by the next() function as well as the value of new iterator which was returned by the prev() function. Hence, the required output was printed.
Characteristics of the Iterators in C++ :
Iterators are capable of accessing, reading, writing, and iterating through container elements. Not all iterators, however, have all of the features. The iterators are shown in the table below, along with their attributes.

Fig. Characteristics of Iterators
Advantages of Iterators in C++ :
There are several examples that demonstrate how iterators are incredibly beneficial to everyone and motivate us to utilize them extensively. The following are some of the advantages of utilizing iterators:
1. Convenience in programming :
It is preferable to use iterators to loop through the contents of containers, because if we do not use an iterator and access elements using the [] operator, we must always be concerned about the container's size, whereas with iterators, we can easily utilize member function end() and make changes through the contents without having to remember anything.
Example :
#include <iostream>
#include <vector>
using namespace std;
int main()
{
// Declaring the vector vect
vector<int> vect = { 10, 20, 30 };
// Declaring the iterator itrtr
vector<int>::iterator itrtr;
int x;
cout << "Without using the iterators = ";
// Accessing elements without the utilization of iterators
for (x = 0; x < 3; ++x)
{
cout << vect[x] << " ";
}
cout << "\nWith using the iterators = ";
// Accessing the elements with the utilization of iterators
for (y = vect.begin(); y != vect.end(); ++y)
{
cout << *y << " ";
}
// Addition of one more element to the vector vect
vect.push_back(4);
cout << "\nWithout using the iterators = ";
// Accessing the elements without the use of the iterators
for (x = 0; x < 4; ++x)
{
cout << vect[x] << " ";
}
cout << "\nWith using the iterators = ";
// Accessing the elements with the utilization of iterators
for (y = vect.begin(); y != vect.end(); ++y)
{
cout << *y << " ";
}
return 0;
}
Output :
Without using the iterators = 10 20 30
With using the iterators = 10 20 30
Without using the iterators = 10 20 30 40
With using the iterators = 10 20 30 40
Explanation :
As it can be seen in the code above, we were needed to maintain a list of the total elements inside the container without utilizing iterators. There have only been three elements at first, but once one more was added, the for loop had to be changed as well. However, because iterators were used, both the time and the for loop stayed the same. The iterators made our job easier and helped us to obtain the output we wanted.
2. Code Reusability :
Consider what would happen if we used a vect list instead of a vector in the preceding program, and instead of utilizing iterators to access the items, we just used the [] operator. This method of accessing would be useless for a list (since lists don't allow random-access iterators). If we had been utilizing iterators for vectors to retrieve the items, simply converting the vector to list in iterator declaration would have sufficed without doing anything further. Iterators improve reusability of programming by allowing access to elements of any container.
3. Container dynamic processing :
Iterators allow us to easily and dynamically, add and delete pieces first from container as needed.
Example :
#include <iostream>
#include <vector>
using namespace std;
int main()
{
// Declaring the vector vect
vector<int> vect = { 10 , 20 , 30 };
// Declaring the iterator itrtr
vector<int>::iterator itrtr;
int x;
// Inserting the element using the iterators
for (y = vect.begin(); y != vect.end(); ++y) {
if (y == vect.begin()) {
y = vect.insert(itrtr, 50);
// inserting 50 at the beginning of the vector vect
}
}
// vect now contains these elements - 50 10 20 30
// Deleting an element by the use of iterators
for (y = vect.begin(); y != vect.end(); ++y) {
if (y == vect.begin() + 1) {
y = vect.erase(y);
// y will now points towards the element which is after the element that is deleted
}
}
// vector vect now contains - 50 20 30
// Accessing the elements of vect using the iterators
for (y = vect.begin(); y != vect.end(); ++y) {
cout << *y << " ";
}
return 0;
}
Output :
50 20 30
Explanation :
As can be seen in the preceding code, we can simply and dynamically, add and remove items from the container utilizing iterators. However, doing so without them would have been extremely arduous because it would have required moving the elements each time prior to insertion and after deletion. Thus we used all the functions like erase(), insert(), begin() and end() to get the required output.
Drawbacks of Iterators in C++ :
We saw how useful iterators are in the last section. However, there are several disadvantages to utilizing iterators. Some of these drawbacks are listed below:
- Iterators don't let you work with two data structures at the same time, especially when the first data structure's contents determine your position in the second.
- Due to the way iterators operate, you can't go back when iterating through a container.
- If you use an iterator to traverse the STL container, the structure cannot be modified while traversing it.
Random Access Iterator vs. Other Iterators :
A Random Access iterator is distinct from other iterators as it overcomes some of the constraints that other iterators have. The following are the major distinctions between the random access iterator and the other iterators:
- Input Iterators vs. Random Access iterators :
They are only accessible. They could only read data from the location where the pointer is pointing; they cannot assign values.
On the other hand in Random Access iterators, the values can be assigned using these iterators.
- Output Iterators vs. Random Access iterators :
The values cannot be accessed via output iterators. These iterators are only for assigning values.
On the other hand, Random Access iterator gives you access to the container's values.
- Forward Iterators vs. Random Access iterators :
These iterators are unidirectional. They can only move ahead, that is, they can only be increased. You can't take them away.
On the other hand, the Random Access iterators work both ways. You may use these iterators to go ahead and backward.
- Bidirectional Iterators vs. Random Access iterators :
The bidirectional iterators don't recognize the offset dereference operator ([]). Dereferencing a bidirectional iterator with the offset operator is not possible.
On the other hand, for dereferencing the variables, the Random Access iterators support using the offset dereferences operator.
Conclusion :
We learnt a lot regarding iterators in C++ in this article. This article discussed many types of iterators and also their applications. The merits and downsides of iterators were then thoroughly examined. We also looked at how much the iterator is useful in its own right.