Last Updated : 08 Apr, 2024
After going through the template definition of various STL algorithms like
std::reverse,
std::next_permutationand
std::reverse_copyyou must have found their template definition consisting of objects of type
Bidirectional Iterator. So what are they and why are they used ?
Bidirectional iteratorsare one of the five main types of iterators present in C++ Standard Library, others being
Input iterators,
Output iterator,
Forward iteratorand
Random - access iterators. Bidirectional iterators are iterators that can be used to access the sequence of elements in a range in
both directions(towards the end and towards the beginning). They are similar to forward iterators, except that they can
move in the backward directionalso, unlike the forward iterators, which can move only in the forward direction. It is to be noted that containers like
list, map, multimap, set and multiset support bidirectional iterators. This means that if we declare normal iterators for them, and then those will be bidirectional iterators, just like in case of vectors and deque they are random-access iterators.
One important thing to be kept in mind is that
random-accessiterators are also valid bidirectional iterators, as shown in the iterator hierarchy above.
Salient Features
A == B // Checking for equality A != B // Checking for inequality
// C++ program to demonstrate bidirectional iterator
#include<iostream>
#include<list>
using namespace std;
int main()
{
list<int>v1 = {1, 2, 3, 4, 5};
// Declaring an iterator
list<int>::iterator i1;
for (i1=v1.begin();i1!=v1.end();++i1)
{
// Assigning values to locations pointed by iterator
*i1 = 1;
}
for (i1=v1.begin();i1!=v1.end();++i1)
{
// Accessing values at locations pointed by iterator
cout << (*i1) << " ";
}
return 0;
}
Output:
1 1 1 1 1So, as we can see here we can both access as well as assign value to the iterator, therefore the iterator is a bidirectional iterator.
A++ // Using post increment operator ++A // Using pre increment operator
// C++ program to demonstrate bidirectional iterator
#include<iostream>
#include<list>
using namespace std;
int main()
{
list<int>v1 = {1, 2, 3, 4, 5};
// Declaring an iterator
list<int>::iterator i1;
// Accessing the elements from end using decrement
// operator
for (i1=v1.end();i1!=v1.begin();--i1)
{
if (i1 != v1.end())
{
cout << (*i1) << " ";
}
}
cout << (*i1);
return 0;
}
Output:
5 4 3 2 1Since, we are starting from the end of the list and then moving towards the beginning by decrementing the pointer, which shows that decrement operator can be used with such iterators. Here, we have run the loop till the iterator becomes equal to the begin(), that is why the first value is not printed inside the loop and we have printed it separately.
Practical implementation
After understanding its features, it is very important to learn about its practical implementation as well. As told earlier, Bidirectional iterators can be used for all the purposes that forward iterator can be used along within those situations where iterator needs to be decremented. The following two STL algorithms can show this fact:
// Definition of std::reverse_copy()
template
OutputIterator reverse_copy(BidirectionalIterator first,
BidirectionalIterator last,
OutputIterator result)
{
while (first != last)
*result++ = *--last;
return result;
}
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.
// Definition of std::random_shuffle()
template
void random_shuffle(RandomAccessIterator first,
RandomAccessIterator last,
RandomNumberGenerator& gen)
{
iterator_traits::difference_type i, n;
n = (last - first);
for (i=n-1; i>0; --i)
{
swap (first[i],first[gen(i+1)]);
}
}
Here, we can see that we have made use of Random-access iterators, as although we can increment a bidirectional iterator, decrement it as well, but we cannot apply arithmetic operator like +, - to it and this what is required in this algorithm , where (last - first) is done, so, for this reason, we cannot use a bidirectional iterator in these scenarios.As we know that Bidirectional iterator is higher in the hierarchy than forward iterator which is itself higher than input and output iterators, therefore, all these three types of iterators can be substituted by bidirectional iterators, without affecting the working of the algorithm. So, the two above examples very well show when, where, why and how bidirectional iterators are used practically.
Limitations
After studying the salient features, one must also know its deficiencies as well although there are not as many as there are in input or output iterators as it is higher in the hierarchy.
If A and B are Bidirectional iterators, then A == B // Allowed A <= B // Not Allowed
If A and B are Bidirectional iterators, then A + 1 // Not allowed B - 2 // Not allowedCPP
// C++ program to demonstrate bidirectional iterator
#include<iostream>
#include<list>
using namespace std;
int main()
{
list<int>v1 = {1, 2, 3, 4, 5};
// Declaring first iterator
list<int>::iterator i1;
// Declaring second iterator
list<int>::iterator i2;
// i1 points to the beginning of the list
i1 = v1.begin();
// i2 points to the end of the list
i2 = v1.end();
// Applying relational operator to them
if ( i1 > i2)
{
cout << "Yes";
}
// This will throw an error because relational
// operators cannot be applied to bidirectional iterators
// Applying arithmetic operator to them
int count = i1 - i2;
// This will also throw an error because arithmetic
// operators cannot be applied to bidirectional iterators
return 0;
}
Output:
Error, because of use of arithmetic and relational operators with bidirectional iterators
If A is a Bidirectional iterator, then A[3] // Not allowed
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4