0% found this document useful (0 votes)
29 views31 pages

Iterators in C++-1

Uploaded by

2 DROPS GAMING
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
29 views31 pages

Iterators in C++-1

Uploaded by

2 DROPS GAMING
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
You are on page 1/ 31

1

Iterators

1.1. Introduction

Overview

 In STL, an iterator is an object that can be used to traverse through or step through the

elements in the container by using a set of operators like increment operator (++) or

dereference operator (*).Iterators are crucial in STL programming as they play an

important role in connecting the algorithms to the container in addition to accessing and

manipulating the data stored inside the containers.

 There are types of Iterators named: input, output, forward, bidirectional and random

access etc.

 Some of the key concepts are: Iteration Protocol, Iterable, Constant & Mutable

Iterators, and Pitfalls etc.

 Iterators are useful for Memory Efficiency, Modularity, and Code Reusability etc.

1.2. Definition

An iterator is used to point to the memory address of the STL container classes Apart from that,

an iterator is also used to iterate over the data structures. It can access or assign values that a

pointer is unable to do. For better understanding, you can relate them with a pointer to some

extent.
2

Iterators act as a bridge that connects algorithm to STL containers and allows the modifications

of the data present inside the container. They allow you to iterate over the container, access and

assign the values, and run different operators over them, to get the desired result. Iterators are

one of the four pillars of the standard template library or STL in C++.

They provide a uniform interface to access elements sequentially without exposing the

underlying structure of the collection.

1.3 Kinds Of Iterators

Depending upon the functionality of iterators they can be classified into five categories, as

shown in the diagram below with the outer one being the most powerful one and consequently

the inner one is the least powerful in terms of functionality.

Fig 1.0

Now each one of these iterators are not supported by all the containers in STL, different containers
support different iterators, like vectors support Random-access iterators, while lists support
bidirectional iterators. The whole list is as given below:

CONTAINER TYPES OF ITERATORS SUPPORTED


3

Vector Random-Access

List Bidirectional

Deque Random-Access

Map Bidirectional

Multimap Bidirectional

Set Bidirectional

Multiset Bidirectional

Stack No iterator Supported

Queue No iterator Supported

Priority No iterator Supported

1.3.1. Types of iterators: Based upon the functionality of the iterators, they can be classified
into five major categories:

1. Input Iterators: They are the weakest of all the iterators and have very limited functionality.

They can only be used in a single-pass algorithms, i.e., those algorithms which process the

container sequentially such that no element is accessed more than once. They are the iterators

that can be used in sequential input operations, where each value pointed by the iterator is read

only once and then the iterator is incremented.


4

Fig 2.0

Note* One important thing to be kept in mind is that forward, bidirectional and random access iterators are also
valid input iterators, as shown in the iterator hierarchy above.

Characteristics Of Input Iterators

A. Usability: Input iterators can be used only with single-pass algorithms, i.e., algorithms
in which we can go to all the locations in the range at most once, like when we have to
search or find any element in the range, we go through the locations at most once.

B. Equality / Inequality Comparison: An input iterator can be compared for equality


with another iterator. Since, iterators point to some location, so the two iterators will be
equal only when they point to the same position, otherwise not. So, the following two
expressions are valid if A and B are input iterators:

A == B // Checking for equality

A != B // Checking for inequality

2. Output Iterators: Just like input iterators, they are also very limited in their functionality and

can only be used in single-pass algorithm, but not for accessing elements, but for being assigned

elements. They can be assigned values in a sequence, but cannot be used to access values, unlike

input iterators which do the reverse of accessing values and cannot be assigned values. So, we

can say that input and output iterators are complementary to each other.
5

Characteristics Of Output Iterators

A. Usability: Just like input iterators, Output iterators can be used only with single-pass
algorithms, i.e., algorithms in which we can go to all the locations in the range at most
once, such that these locations can be dereferenced or assigned value only once.

B. Equality / Inequality Comparison: Unlike input iterators, output iterators cannot be


compared for equality with another iterator. So, the following two expressions are invalid
if A and B are output iterators:

A == B // Invalid - Checking for equality

A != B // Invalid - Checking for inequality

3. Forward Iterator: They are higher in hierarchy than input and output iterators, and contain

all the features present in these two iterators. But, as the name suggests, they also can only move

in forward direction and that too one step at a time. Forward iterators are considered to be the

combination of input as well as output iterators. It provides support to the functionality of both of

them. It permits values to be both accessed and modified.

std::replace: As we know this algorithm is used to replace all the elements in the range which

are equal to a particular value by a new value. So, let us look at its internal working
6

4. Bidirectional Iterators: They have all the features of forward iterators along with the fact that

they overcome the drawback of forward iterators, as they can move in both the directions that is

why their name is bidirectional.

std::reverse_copy: As the name suggests, this algorithm is used to copy a range into another

range, but in reverse order. Now, as far as accessing elements and assigning elements are

concerned, forward iterators are fine, but as soon as we have to decrement the iterator, then

we cannot use these forward iterators for this purpose, and that’s where bidirectional iterators

come for our rescue.

Here, we can see that we have declared last as a bidirectional iterator, as we cannot decrement a
forward iterator as done in case of last, so we cannot use it in this scenario, and we have to
declare it as a bidirectional iterator only.

5. Random-Access Iterators: They are the most powerful iterators. They are not limited to

moving sequentially, as their name suggests, they can randomly access any element inside the

container. They are the ones whose functionality is same as pointers. Random-access iterators
7

are the most complete iterators in terms of functionality. All pointer types are also valid random-

access iterators.

Characteristics Of Random-Access Iterators

A. Usability: Random-access iterators can be used in multi-pass algorithms, i.e.,


algorithm which involves processing the container several times in various passes.

B. Equality / Inequality Comparison: A Random-access iterator can be compared for


equality with another iterator. Since, iterators point to some location, so the two iterators
will be equal only when they point to the same position, otherwise not. So, the following
two expressions are valid if A and B are Random-access iterators:

A == B // Checking for equality

A != B // Checking for inequality

1.4 Benefits Of Iterators

There are certainly quite a few ways which show that iterators are extremely useful to us and

encourage us to use it profoundly. Some of the benefits of using iterators are as listed below:

1. Convenience in programming: It is better to use iterators to iterate through the contents of

containers, as if we will not use an iterator and access elements using ‘[ ]’ operator, then we need

to be always vary of the size of the container, whereas with iterators we can simply use member

function ‘end ()’ and iterate through the contents without having to keep anything in mind.
8
9

Output:

Fig 3.0

Explanation: As can be seen in the above code that without using iterators we need to keep track
of the total elements in the container. In the beginning there were only three elements, but after
one more element was inserted into it, accordingly the for loop also had to be amended, but using
iterators, both the time the for loop remained the same. So, iterator eased our task.

2. Code reusability: Now consider if we make v a list in place of vector in the above program

and if we were not using iterators to access the elements and only using ‘[ ]’ operator, then in

that case this way of accessing was of no use for list (as they do not support random-access

iterators).

However, if we were using iterators for vectors to access the elements, then just

changing the vector to list in the declaration of the iterator would have served the purpose,

without doing anything else So, iterators support reusability of code, as they can be used to

access elements of any container.

3. Dynamic processing of container: Iterators provide us the ability to dynamically add or

remove elements from the container as and when we want with ease.
10

Output:

Fig 4.0
Explanation: As seen in the above code, we can easily and dynamically add and remove
elements from the container using iterator, however doing the same without using them would
have been very tedious as it would require shifting the elements every time before insertion and
after deletion.

Iterators are powerful tools that allow efficient traversal and processing of collections and

sequences in Python. By understanding the various types of iterators, from built-in and file

iterators to custom and infinite iterators, you can handle a wide range of tasks more effectively

and elegantly.
11

2.0.Pitfall: Iterator-Based Compiler Issues


Iterators offer a consistent interface for navigating and modifying container items, making them

a strong and essential component of C++'s Standard Template Library (STL). Their application

is not without difficulties, though. Iterator compilation issues can result in a number of traps that

programmers need to avoid in order to create reliable and effective C++ applications.

Here, we go into further information about these traps:

2.1. Undefined Behavior

Having undefined behavior when working with iterators is a big problem. When iterators are

used improperly, as when dereferencing an iterator that hasn't been initialized or that has been

rendered invalid by changes made to the container, this can happen. For instance, iterators that

are already in place may become invalid when elements are added to or removed from a

container such as ‘std::vector’. Using these invalidated iterators may lead to crashes, erratic

programme behavior, or difficult-to-debug subtle defects.


12

Example

Output

The output of this code is unpredictable and may cause a runtime crash or print a garbage value

because it is invalidated after erase.

2.2. Performance Overheads


13

Performance overheads from iterators can be introduced, especially in debug builds. In order to

guarantee the validity of iterators, compilers frequently include extra safety tests in debug mode,

such as range checks and iterator validity checks. These checks can greatly slow down the

program's execution, even though they are useful for finding flaws during development. Since

these tests are usually turned off in release builds to maximize performance, the performance

penalty is usually less of an issue.

Example

Output:

In debug mode, this might run significantly slower due to iterator checks, but in release mode, it

will run much faster due to the absence of these checks.


14

2.3.Compatibility Issues

Differences in STL implementations between compilers and compiler versions might cause

compatibility problems. The behavior and interface of iterators are specified in the C++ standard,

but implementation details may vary. When using complex iterator features or transferring code

between various compiler environments, this can cause issues. For example, some extensions or

optimizations that are present in one compiler's STL could not be in another, leading to

compatibility issues and necessitating code changes.

Example

Output:

The output should be consistent, but some older or non-standard-compliant compilers may

exhibit different behaviors, potentially leading to unexpected results.


15

2.4.Complex Error Messages

Iterator-related compiler warning messages can be infamously complicated and challenging to

understand, particularly in programmes with a lot of templates. Upon encountering a mistake, the

compiler frequently generates lengthy and complex warnings that may mask the true issue. This

is especially true for template instantiation failures, when the real problem could be buried in a

lengthy sequence of template expansions. To find the core reason, developers must meticulously

go back through the error messages, which can be a laborious and annoying process.

Example
16

Output:

If the iterator type is incorrect, the compiler error message can be long and complex, making it

hard to identify the exact issue.

2.5.Iterator Invalidations

Iterator-related compiler warning messages can be infamously complicated and challenging to

understand, particularly in programmes with a lot of templates. Upon encountering a mistake, the

compiler frequently generates lengthy and complex warnings that may mask the true issue. This

is especially true for template instantiation failures, when the real problem could be buried in a

lengthy sequence of template expansions. To find the core reason, developers must meticulously

go back through the error messages, which can be a laborious and annoying process.

Example
17

Output:

The first ‘std::cout’ prints 1, but the second ‘std::cout’ results in undefined behavior due to

iterator invalidation after insert.

2.6.Iterator Category Mismatch

Iterators of a certain category are frequently needed for STL algorithms. For instance, ‘std::

find’ can function with input iterators, while ‘std::sort’ needs random access iterators. When

using an algorithm with an iterator of the wrong category, compile-time errors or erroneous

behavior may result. Correct programme operation requires knowing each algorithm's

requirements and making sure the right kind of iterator is utilized.

Example

Output:
18

2.7.Concurrency Issues

Iterators in multi-threaded settings may result in unclear behavior and data races if the

underlying container is changed concurrently without appropriate synchronization. Since

iterators are not thread-safe by nature, multiple threads can modify a container at the same time,

corrupting the container's state and invalidating iterators. Iterators and the containers they are

associated with must be accessed properly in a multi-threaded context, which requires the

appropriate usage of synchronization methods like mutexes.

Example
19

Output:

Without proper locking, the output may be unpredictable, with potential data races causing

undefined behavior. With the lock, the output will be consistent and correct.

2.8.Iterator Traits Misuse

A useful tool in template metaprogramming for figuring out an iterator's characteristics is its

trait. However, serious issues with generic programming might arise from misinterpreting or

abusing iterator features. For instance, in order to guarantee accuracy or maximize performance,

algorithms may depend on particular characteristics. Erroneous characteristics may lead to

algorithmic failure or subpar performance. To properly utilize iterator qualities and steer clear of

associated dangers, developers must possess a strong understanding of them.

Example
20

Output

If the iterator traits are misused or misunderstood, the function might not correctly identify the

iterator category, leading to incorrect behavior in generic algorithms.


21

2.9.Lack of Support for Custom Containers

Custom containers that support iterators must comply with the STL's specified interface

requirements. This can be difficult and prone to mistakes, particularly for developers who are not

well-versed in STL conventions. Implementing different iterator actions and making sure they

follow the expected behavior of standard iterators are necessary for proper implementation.

Neglecting to accomplish this may result in inconspicuous errors and problems with STL

algorithms' compatibility.

Example
22

Output:

If the iterator traits are misused or misunderstood, the function might not correctly identify the

iterator category, leading to incorrect behavior in generic algorithms.

3.0.Constant and Mutable Iterators in C++


23

3.1. Constants Iterators

Iterators that point to elements in a container but prevent changes to the elements they point to

are known as constant iterators. They guarantee that the elements cannot be unintentionally or

purposely changed by the iterator, which is crucial when the integrity of the data inside the

container needs to be maintained.

Usage and Benefits

 Read-exclusively Access: The components of a container can be accessed exclusively by

means of constant iterators. This is helpful in situations when maintaining data integrity

throughout the traversal process is essential.

 Safety: Constant iterators assist prevent unintentional side effects and issues that can

come from accidentally changing container elements by blocking alterations.

 Code Clarity: By expressing that the elements being accessed should not and cannot be

updated, the use of constant iterators clarifies the intent of the code.

Example
24

In this example, ‘const_iterator’ is used to iterate through the vector vec. Since the iterator is

constant, trying to modify the elements (e.g., *it = 10;) would result in a compilation error.

Output:

3.2. Mutable Iterators


25

However, elements that they point to can be modified using mutable iterators. Read and write

operations are made possible by their complete access to the container's elements. When it comes

to traversing a container and having to make changes to its elements, mutable iterators are

employed.

Usage and Benefits

 Modification Capability: During iteration, mutable iterators are necessary if elements

inside a container need to be updated, removed, or changed in any other way.

 Flexibility: They enable both retrieval and modification of the container pieces and offer

a broad variety of operations on them.

 Algorithm Compatibility: In order to make in-place changes to container elements,

mutable iterators are necessary for a number of STL algorithms.

Example

In this example, iterator is used to iterate through the vector vec and modify each element by

doubling its value. The second loop then prints the modified elements.
26

Output

Detailed Explanation

##Declaration and Usage

 Constant Iterators: Declared using the const_iterator type provided by the container. Use

‘cbegin()’ and ‘cend()’ member functions to obtain constant iterators.


27

 Mutable Iterators: Declared using the iterator type provided by the container. Use ‘begin()’ and

‘end()’ member functions to obtain mutable iterators.

3.3. Common Operations

 Increment and Decrement: Both constant and mutable iterators support the increment

(++) and decrement (--) operations.

 Dereferencing: Both types can be dereferenced using the * operator. For constant

iterators, the dereferenced value is read-only.

 Comparison: Both types support comparison operations (==, !=, <, >, <=, >=) to

determine the position within the container.

In C++ programming, constant and mutable iterators have different functions and provide

different degrees of access to container items. Mutable iterators offer flexibility for dynamic

updates and modifications, while constant iterators priorities data integrity by limiting

modifications. Developers can utilize these iterators to safely and efficiently modify container

data by knowing their properties and applications.


28

Executive Summary & Conclusion

A fundamental component of the C++ Standard Template Library, iterators offers a strong and

adaptable way to retrieve and modify container items. They do have some possible drawbacks,

though, such as undefined behavior, performance overheads, compatibility problems, confusing

warning messages, iterator invalidations, mismatched categories of iterators, concurrency

problems, mishandling of iterator traits, and the difficulty of maintaining customised containers.

It is essential to comprehend these hazards and know how to avoid them in order to write reliable

and effective C++ programmes. Leveraging the full capability of iterators while avoiding their

usual pitfalls requires careful coding methods, comprehensive testing, and proper understanding.
29

References

1. "The C++ Programming Language" by Bjarne Stroustrup


2. "C++ Standard Library: A Tutorial and Reference" by Nicolai M. Josuttis
3. C++ Reference - Iterators
4. cplusplus.com - Iterators
5. GeeksforGeeks - Iterators in C++
6. California State University, Long Beach(pdf) - Introduction to Iterators in C++
7. Simplearn.com - Iterators in C++: An Ultimate Guide to Iterators.
8. "Effective STL: 50 Specific Ways to Improve Your Use of the Standard Template
Library" by Scott Meyers
30
31

You might also like