×

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.

C++ Iterators

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:

C++ Iterators

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.

C++ Iterators

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.


Related Topics

Pattern programs in C++

In this article, we are going to discuss different pattern programs in C++. Program for Printing * patterns: Right Angle Triangle* pattern #include <iostream> using namespace std; int main() {     int rows;     cout <<...

3 minutes read.

C++ Features

C++ is a general-purpose programming language that evolved from the C language to include an object-oriented paradigm. It is a compiled and imperative language. Object-Oriented Programming Object-oriented programming language concepts: ClassObjectsEncapsulationPolymorphismInheritanceAbstraction Class: A Class...

4 minutes read.

How to create a stack in C++

A stack is a data structure, which is of linear type. A specific order has to be followed while inserting and deleting the elements from the stack. Generally, stack follows...

5 minutes read.

Nullptr in C++

What is Nullptr in C++? A null pointer value is represented by the term nullptr. Use a null pointer value to indicate that a native pointer type, inner pointer, or object...

3 minutes read.

Implementing the sets without C++ STL containers

Many practical features and tools in C++ support us in programming competitions. One of these parts is a set from the Standard Template Library (STL), which offers an effective way...

6 minutes read.

How the value is passed in C++

Introduction: The call-by-value method of giving arguments to a function duplicates the real value of an argument into the formal parameter of the function. In this instance, modifications to the parameter...

5 minutes read.

C++ array to function

Arrays in C++ : Instead of defining distinct variables for each item, arrays are used to hold numerous values in a single variable. An array can be declared by specifying the variable...

4 minutes read.

C++ Data Abstraction

Object-oriented programming (OOP) provides a number of characteristics that enable programmers to design programmes based on a variety of ideas, reducing errors and increasing program flexibility. The abstraction of data...

7 minutes read.

Constructor Overloading in C++

A Constructor is a class member function that is used to initialize the class's objects. Constructors have no return type and are called automatically when an object is formed. Constructor Characteristics Constructors...

3 minutes read.

Functors in C++

Functors are not a very popular thing among beginner or intermediate-level programmers. But this thing is very useful and helpful. The name functor suggests us some similarities with function. It...

3 minutes read.

LCM Program in C++

What is LCM? LCM is an acronym for "least common multiple". It is used to discover the lowest positive integer divisible by all integers (whose LCM is calculated). For instance, the...

4 minutes read.

OOPs Concepts in C++

C++ Object-Oriented Programming Concepts C++ uses the concept of object-oriented programming. Object Oriented Programming has some prominent features: Object Class Data abstraction Encapsulation Polymorphism Inheritance Message passing Object An object is the basic unit...

2 minutes read.

Object in C++

In this article, we will learn about Object in C++. In short, an object is a stateful entity with behaviour. Data is referred to as state, and functionality is referred to...

3 minutes read.

Hospital Management Project in C++

The following capabilities are required to build a hospital management project: These are as follows: hospitals' names, contact information, and lists of doctors and patients. Activities Supported Hospital Data Print Patients' data to...

4 minutes read.

C ++ Program: Alphabet Triangle and Number Triangle

Alphabet Triangle and Number Triangle An alphabet triangle is a triangle that typically looks like a pyramid or other triangles like an isosceles triangle, a right-angled triangle consisting of similar or...

4 minutes read.

Data Hiding in C++

C++ : High-performance apps can be made using the cross-platform language C++. Bjarne Stroustrup created C++ as an addition to the C language. Programmers have extensive control over memory and system...

3 minutes read.

Pointer to Object in C++

What is a pointer? A pointer in C++ is used to point the variable by storing the address of the variable. In C++, to print the address of the variable, we...

4 minutes read.

Precision of floating point numbers Using these functions floor(), ceil(), trunc(), round() and setprecision() in C++

Precision of floating point numbers Using these functions floor(), ceil(), trunc(), round() and setprecision() in C++ 1/2 decimal equal is 0.555555555555555555555 .... An indefinite number of lengths will require the storage...

4 minutes read.

abs() function in C++

In C++, the abs() function returns the absolute value of any integer number. Using this function a negative integer is multiplied by -1 and positive number or zero is returned...

4 minutes read.

Divide by Zero Exception in C++

We use exception handling method to handle the divide by zero exception. Dividing a number with zero is generally mathematical error. We have to exception handling method to overcome this...

2 minutes read.