AlgoMaster Logo

Iterators Basics

Last Updated: January 3, 2026

6 min read

There’s something enchanting about iterators in C++. They allow us to navigate through collections seamlessly, almost like magic.

When you think about it, they make your life easier by abstracting the complexity of data structures. Instead of worrying about the underlying mechanics of a container, you can focus on what you want to accomplish with the data.

In this chapter, we will dive into the basics of iterators, exploring their purpose, how they work, and why they are such a vital part of C++. We'll look at practical examples, common use cases, and some nuances that can trip up even experienced developers.

What is an Iterator?

At its core, an iterator is an object that allows you to traverse a container, like a vector or a list, without exposing the underlying structure of that container. Think of it as a pointer that moves through the elements of a collection, one element at a time. This concept is powerful because it provides a uniform interface for accessing data, regardless of how that data is stored.

The Iterator Interface

In C++, an iterator typically supports the following operations:

  • Increment: Move to the next element.
  • Dereference: Access the value of the current element.
  • Equality/Inequality: Compare iterators to see if they refer to the same element.

Here’s a simple example demonstrating these operations in action:

In this example, we create a vector of integers and use an iterator to print each element. Notice how we use the begin() method to initialize the iterator and end() to check when we’ve reached the end of the vector.

Benefits of Using Iterators

Iterators provide several advantages that make them a go-to choice for traversing containers:

  1. Abstraction: They abstract away the details of the underlying data structure. Whether you're using a vector, list, or map, the way you traverse them remains consistent.
  2. Flexibility: You can write functions that work with any container type, as long as it provides iterators. This promotes code reusability.
  3. Safety: Iterators help reduce the risk of errors that come from directly manipulating indexes, such as going out of bounds.
  4. Algorithms: Many of the standard algorithms in the C++ Standard Library are designed to work with iterators, making them powerful tools for data manipulation.

Here’s an example showing how iterators allow for a generic function:

In this snippet, the printElements function can work with both a vector and a list, showcasing the flexibility of iterators.

Common Iterator Types

While we won’t delve deeply into iterator types (that’s for the next chapter), it's worth noting that there are several kinds of iterators in C++, including:

  • Input Iterators: Read data from a container.
  • Output Iterators: Write data to a container.
  • Forward Iterators: Can read and write data, and can only move in one direction.
  • Bidirectional Iterators: Move in both directions.
  • Random Access Iterators: Allow direct access to any element in the container.

Understanding these types is essential because they dictate how you can use an iterator, including what operations are permissible.

Iterating with Standard Algorithms

C++ provides a rich set of standard algorithms that work seamlessly with iterators. Functions like std::for_each, std::find, and std::transform are great examples.

Here’s how you can utilize std::for_each:

In this example, std::for_each applies a lambda function to each element of the vector, demonstrating how iterators can streamline operations on collections.

Nuances and Common Mistakes

While iterators are incredibly useful, there are some common pitfalls you should be aware of:

  1. Invalidation: Certain operations can invalidate iterators. For example, adding an element to a vector may invalidate all iterators pointing to that vector. Be cautious when modifying a container while iterating through it.
  2. Dereferencing End Iterators: Never attempt to dereference an iterator that is equal to the end of a container. This leads to undefined behavior.
  3. Iterator Types: Using the wrong type of iterator for specific operations can lead to compilation errors. For instance, trying to use an output iterator where an input iterator is required.

Here’s an example that illustrates the invalidation issue:

In this snippet, after modifying the vector, the iterator becomes invalid, leading to potentially dangerous behavior.

Practical Uses of Iterators

Iterators are not just theoretical constructs; they have many practical applications. Here are a few:

  • Data Processing: Use iterators to process data in a pipeline, applying transformations or filtering.
  • Game Development: Iterate through game objects for rendering or updating their states.
  • File Processing: Use iterators to read from files line by line or to process chunks of data.

As developers, leveraging iterators effectively can lead to cleaner, more maintainable code. For example, consider a use case where we want to filter out even numbers from a list:

In this example, std::copy_if uses iterators to filter the odd numbers from a vector, demonstrating how iterators can simplify data processing tasks.