For working professionals
For fresh graduates
More
4. C++ Variable
10. C++ for Loop
12. C++ Lambda
13. Loop in C++
15. Array in C++
16. Strings in C++
17. Substring in C++
29. Vector in C++
30. Map in C++
31. Pair in C++
33. Iterators in C++
34. Queue in C++
36. Stack in C++
37. ifstream in C++
40. Templates in C++
43. Namespace in C++
46. Recursion in C++
48. C++ Shell
49. Setw in C++
51. Atoi in C++
54. C# vs C++
55. C++ GUI
56. C++ Game Code
57. Class in C++
58. C++ Header Files
63. Cin in C++
64. Printf in C++
65. Struct in C++
66. C++ List
68. C++ Comments
72. Sorting in C++
Iterators are essential in C++ programming. They support data traversal and we can think of them as generalized pointers that extend the concept of pointing to a specific memory location.
I like to think that iterators in C++ act as our trusty guides, leading us through the complex pathways of our collections. But what exactly are these iterators, and why are they so fundamental to the C++ experience? That’s exactly what we will learn in this guide.
In this tutorial, we will learn everything about iterators and explore their different types, the operations they support, and how to use them effectively with STL containers. I’ll help you use iterators with confidence, effortlessly being able to traverse and manipulate your data with the elegance and efficiency that C++ offers.
Let us learn more.
Unlike raw pointers, which directly manipulate memory addresses, iterators in C++ provide a higher-level abstraction. They offer a consistent and standardized way to access and manipulate elements within various container types, such as vectors, lists, maps, and more.
This abstraction is where the true power of iterators in C++ lies. By decoupling the act of iteration from the specific implementation details of the underlying data structure, iterators unlock the door to generic programming. Iterators allow us to write algorithms that work seamlessly with a wide range of containers, without having to rewrite the code for each specific type.
The Standard Template Library (STL), the crown jewel of C++, owes much of its power and flexibility to iterators. STL algorithms like std::sort, std::find, and std::transform operate on ranges defined by iterators, making them incredibly versatile and reusable.
C++ offers a rich taxonomy of iterators, each tailored to specific access patterns and operations. Understanding their unique characteristics empowers you to choose the right tool for the job, ensuring efficient and safe data manipulation. By choosing the right cpp iterator type for our specific task, we can harness the full power of the C++ STL and write efficient generic code.
Input iterators are the simplest and most restrictive type. They are read-only, single-pass iterators, meaning you can only move forward through the data once, and you can only access the elements, not modify them. These iterators in C++ are often used for reading data from input streams or in algorithms that don't require modifying the underlying data.
(Example) Reading integers from a file:
std::ifstream inputFile("data.txt");
std::istream_iterator<int> start(inputFile), end;
std::vector<int> numbers(start, end); // Read all integers into a vector
Forward iterators in C++ build upon input and output iterators, allowing both reading and writing while still maintaining the single direction restriction. They enable multiple passes over the data, making them suitable for algorithms that modify elements or require multiple readings.
(Example) Modifying elements in a list:
std::ofstream outputFile("output.txt");
std::ostream_iterator<int> outputIterator(outputFile, " ");
std::vector<int> data = {1, 2, 3, 4, 5};
std::copy(data.begin(), data.end(), outputIterator); // Write vector to file
Bidirectional iterators enhance forward iterators with the ability to move backward as well as forward. This added flexibility makes them indispensable for algorithms that require traversing data in both directions, such as reversing a sequence or searching for elements in either direction.
(Example) Reversing a set:
std::set<int> numbers = {5, 2, 8, 1};
std::set<int>::reverse_iterator rit;
for (rit = numbers.rbegin(); rit != numbers.rend(); ++rit) {
std::cout << *rit << " "; // Output: 8 5 2 1
}
Random access iterators are the most powerful and versatile. These iterators in C++ offer constant-time access to any element within the container, much like accessing elements in an array using indices. This capability is essential for algorithms that rely on efficient random access, like sorting or binary search.
(Example) Sorting a vector:
std::vector<int> numbers = {5, 2, 8, 1};
std::sort(numbers.begin(), numbers.end());
// Sorts the vector in ascending order using random access iterators
These iterators in C++ provide intuitive mechanisms for moving through your data structures:
For bidirectional and random-access iterators, you can also use --iter and iter-- to move backward through the data.
The * operator, when applied to an iterator, reveals the element it points to.
Example (with C++ vector iterator):
std::vector<int> numbers = {1, 2, 3, 4, 5};
std::vector<int>::iterator it = numbers.begin();
std::cout << *it << std::endl; // Output: 1
If the iterator is mutable (i.e., not a const_iterator), you can even modify the element directly:
*it = 10; // Changes the first element of the vector to 10
Iterators also provide the means to compare their positions relative to each other:
Example:
for (auto it = numbers.begin(); it != numbers.end(); ++it) { ... }
Example:
std::vector<int>::iterator it1 = numbers.begin();
std::vector<int>::iterator it2 = numbers.begin() + 2;
if (it1 < it2) { ... } // it1 points to an earlier element than it2
Now that you have a solid understanding of cpp iterator types and basic operations, let us explore how to harness their power within the vast landscape of the Standard Template Library (STL) containers.
Every STL container, whether it's a vector, list, map, or set, offers two essential member functions: begin() and end(). These functions act as the entry and exit points for traversing your data using iterators.
Let's see how to use begin() and end() in a for loop to iterate over a vector:
std::vector<int> numbers = {1, 2, 3, 4, 5};
for (std::vector<int>::iterator it = numbers.begin(); it != numbers.end(); ++it) {
std::cout << *it << " "; // Output: 1 2 3 4 5
}
In this loop, it starts at numbers.begin() and moves forward with each iteration until it reaches numbers.end(). During each iteration, we dereference it to access and print the current element.
For added convenience, C++11 introduced range-based for loops, which simplify iteration even further:
for (const int& num : numbers) {
std::cout << num << " "; // Output: 1 2 3 4 5
}
Behind the scenes, the range-based for loop also uses iterators, but it automatically handles their initialization, increment, and comparison with end().
Iterators truly shine when used with the vast array of algorithms provided by the STL. These algorithms, such as std::find, std::sort, and std::transform, operate on ranges defined by iterators, making them incredibly flexible and applicable to various containers.
(Example) Finding an element in a vector:
std::vector<int>::iterator it = std::find(numbers.begin(), numbers.end(), 3);
if (it != numbers.end()) {
std::cout << "Found 3 at position: " << std::distance(numbers.begin(), it) << std::endl;
}
Many STL containers offer additional member functions that return iterators, providing specialized ways to interact with their elements. By leveraging these functions, you can efficiently manipulate the contents of your containers while maintaining the integrity of their underlying data structures.
For example:
Here is an example of a C++ list iterator program (with std::list)that you can run yourself.
Code:
#include <iostream>
#include <list>
#include <algorithm>
int main() {
// Create a list of integers
std::list<int> numbers = {7, 5, 16, 8, 25, 13};
// Display original list
std::cout << "Original list: ";
for (int num : numbers) {
std::cout << num << " ";
}
std::cout << std::endl;
// 1. Iterating and modifying elements
for (std::list<int>::iterator it = numbers.begin(); it != numbers.end(); ++it) {
*it += 1; // Increment each element by 1
}
// 2. Finding an element (using std::find)
std::list<int>::iterator it = std::find(numbers.begin(), numbers.end(), 17);
if (it != numbers.end()) {
std::cout << "Found 17 in the list at position: "
<< std::distance(numbers.begin(), it) << std::endl;
} else {
std::cout << "17 not found in the list." << std::endl;
}
// 3. Inserting an element (using insert)
it = numbers.begin();
std::advance(it, 2); // Move iterator to the third position
numbers.insert(it, 99);
// 4. Deleting an element (using erase)
it = std::find(numbers.begin(), numbers.end(), 26);
if (it != numbers.end()) {
numbers.erase(it);
}
// 5. Iterating in reverse (using reverse_iterator)
std::cout << "Reversed list: ";
for (std::list<int>::reverse_iterator rit = numbers.rbegin(); rit != numbers.rend(); ++rit) {
std::cout << *rit << " ";
}
std::cout << std::endl;
return 0;
}
You now know how to C++ create iterator. If you wish to learn how to code in C++, you can check out upGrad’s software engineering courses.
As you become more adept at wielding iterators, you will discover a range of advanced techniques that offer even greater flexibility and control over how you interact with data. Let us explore some of these techniques to elevate your iterator game.
In certain scenarios, you might want to ensure that the data within a container remains unchanged during iteration. This is where const iterators come to the rescue. They act as guardians, preventing any modifications to the elements they point to.
To obtain a const iterator, you can use the cbegin() and cend() member functions of STL containers:
std::vector<int> numbers = {1, 2, 3, 4, 5};
for (std::vector<int>::const_iterator it = numbers.cbegin(); it != numbers.cend(); ++it) {
// *it = 10; // This would be an error, as it tries to modify the element
std::cout << *it << " "; // Output: 1 2 3 4 5
}
In this example, attempting to modify the elements through the it iterator would result in a compilation error, ensuring the integrity of the data.
Sometimes, you need to traverse your data in reverse order. Reverse iterators provide a convenient way to do this. Reverse iterators in C++ offer the same operations as regular iterators, but they move backward through the container.
You can obtain reverse iterators using rbegin() and rend() member functions:
std::list<int> numbers = {1, 2, 3, 4, 5};
for (std::list<int>::reverse_iterator rit = numbers.rbegin(); rit != numbers.rend(); ++rit) {
std::cout << *rit << " "; // Output: 5 4 3 2 1
}
Note that rbegin() points to the last element, and rend() points before the first element. Incrementing a reverse iterator actually moves it backward through the container.
Iterator adapters are special iterators that modify the behavior of existing iterators to suit specific tasks. They act as intermediaries, providing a customized interface for interacting with data.
Example:
std::vector<int> numbers = {1, 2, 3};
std::fill_n(std::back_inserter(numbers), 2, 0); // Appends two zeros to the vector
By understanding iterator operations, we unlock the ability to navigate and manipulate data structures in C++ with unparalleled flexibility and control. Whether we are iterating over a list, searching for a specific element, or transforming data in place, iterators provide the tools we need to achieve our goals with elegance and efficiency.
If you wish to learn programming languages such as C++, you can check out upGrad’s computer science programs such as the Master’s in Computer Science Program.
An iterator is an object in C++ that acts as a generalized pointer, allowing traversal and manipulation of elements within containers like vectors and lists.
There are five main types: input, output, forward, bidirectional, and random access iterators, each offering varying levels of functionality and access capabilities.
While both point to elements, iterators provide a higher-level abstraction, working with various containers and supporting operations like incrementing and dereferencing.
Iterators in C++ are obtained using member functions like begin(), (start) and end() (one past the end), and then used in loops or algorithms to access and modify container elements.
begin() returns an iterator pointing to the first element, while end() returns an iterator pointing one position past the last element, acting as a stopping point.
Yes, if the iterator is not const, we can modify the element it points to using the dereference operator (*).
Iterators provide a consistent way to work with different container types, enabling generic algorithms and abstracting the underlying data structure for flexibility.
Not exactly. Iterators are objects that behave like pointers, but they can have more complex internal structures and offer additional functionalities beyond simple memory addressing.
Author
Start Learning For Free
Explore Our Free Software Tutorials and Elevate your Career.
Talk to our experts. We are available 7 days a week, 9 AM to 12 AM (midnight)
Indian Nationals
1800 210 2020
Foreign Nationals
+918045604032
1.The above statistics depend on various factors and individual results may vary. Past performance is no guarantee of future results.
2.The student assumes full responsibility for all expenses associated with visas, travel, & related costs. upGrad does not provide any a.