iteratior


Header: <iterator>

The <iterator> header is part of the C++ Standard Library that provides a set of classes and functions for working with iterators. Iterators are a generalization of pointers, used to access elements in containers or sequences. This header defines several iterator categories, iterator traits, and utility functions that facilitate the implementation and use of iterators in C++ programs.

Key Characteristics

Example 1: Basic Usage of Iterator Categories and Traits

#include <iostream>
#include <vector>
#include <list>
#include <iterator>

template <typename Iterator>
void print_iterator_category(const Iterator& it) {
    if (std::is_same_v<typename std::iterator_traits<Iterator>::iterator_category, std::random_access_iterator_tag>)
        std::cout << "Random Access Iterator" << std::endl;
    else if (std::is_same_v<typename std::iterator_traits<Iterator>::iterator_category, std::bidirectional_iterator_tag>)
        std::cout << "Bidirectional Iterator" << std::endl;
    else if (std::is_same_v<typename std::iterator_traits<Iterator>::iterator_category, std::forward_iterator_tag>)
        std::cout << "Forward Iterator" << std::endl;
    else if (std::is_same_v<typename std::iterator_traits<Iterator>::iterator_category, std::input_iterator_tag>)
        std::cout << "Input Iterator" << std::endl;
    else if (std::is_same_v<typename std::iterator_traits<Iterator>::iterator_category, std::output_iterator_tag>)
        std::cout << "Output Iterator" << std::endl;
}

int main() {
    std::vector<int> vec = {1, 2, 3, 4, 5};
    std::list<int> lst = {1, 2, 3, 4, 5};

    std::cout << "Vector iterator category: ";
    print_iterator_category(vec.begin());

    std::cout << "List iterator category: ";
    print_iterator_category(lst.begin());

    return 0;
}

Explanation:

Example 2: Using Reverse Iterators

#include <iostream>
#include <vector>
#include <iterator>
#include <algorithm>

int main() {
    std::vector<int> numbers = {1, 2, 3, 4, 5};

    std::cout << "Forward iteration: ";
    for (auto it = numbers.begin(); it != numbers.end(); ++it) {
        std::cout << *it << " ";
    }
    std::cout << std::endl;

    std::cout << "Reverse iteration: ";
    for (auto rit = numbers.rbegin(); rit != numbers.rend(); ++rit) {
        std::cout << *rit << " ";
    }
    std::cout << std::endl;

    // Using reverse iterators with algorithms
    std::cout << "Reverse sorted: ";
    std::sort(numbers.rbegin(), numbers.rend());
    for (int num : numbers) {
        std::cout << num << " ";
    }
    std::cout << std::endl;

    return 0;
}

Explanation:

Example 3: Stream Iterators for I/O Operations

#include <iostream>
#include <iterator>
#include <vector>
#include <algorithm>
#include <sstream>

int main() {
    // Reading from standard input
    std::cout << "Enter numbers (Ctrl+D to end):" << std::endl;
    // Use { } to interpret expression as initializers
    std::vector<int> numbers{std::istream_iterator<int>(std::cin), std::istream_iterator<int>()};

    // Writing to standard output
    std::cout << "You entered: ";
    std::copy(numbers.begin(), numbers.end(), std::ostream_iterator<int>(std::cout, " "));
    std::cout << std::endl;

    // Using stringstream with stream iterators
    std::stringstream ss("10 20 30 40 50");
    // Use { } to interpret expression as initializers
    std::vector<int> more_numbers{std::istream_iterator<int>(ss), std::istream_iterator<int>()};

    std::cout << "Numbers from stringstream: ";
    std::copy(more_numbers.begin(), more_numbers.end(), std::ostream_iterator<int>(std::cout, " "));
    std::cout << std::endl;

    return 0;
}

Explanation:

Example 4: Custom Iterator Implementation

#include <iostream>
#include <iterator>

class Fibonacci {
private:
    int current;
    int next;

public:
    class iterator {
    private:
        int current;
        int next;
    public:
        using iterator_category = std::input_iterator_tag;
        using value_type = int;
        using difference_type = std::ptrdiff_t;
        using pointer = const int*;
        using reference = const int&;

        iterator(int current = 0, int next = 1) : current(current), next(next) {}

        int operator*() const { return current; }
        iterator& operator++() {
            int temp = current;
            current = next;
            next = temp + next;
            return *this;
        }
        iterator operator++(int) {
            iterator temp = *this;
            ++(*this);
            return temp;
        }
        bool operator==(const iterator& other) const { return current == other.current; }
        bool operator!=(const iterator& other) const { return !(*this == other); }
    };

    Fibonacci() : current(0), next(1) {}
    iterator begin() { return iterator(); }
    iterator end() { return iterator(89); } // Arbitrary end point
};

int main() {
    Fibonacci fib;
    std::cout << "First 10 Fibonacci numbers: ";
    int count = 0;
    for (auto i : fib) {
        if (count++ == 10) break;
        std::cout << i << " ";
    }
    std::cout << std::endl;

    return 0;
}

Explanation:

Example 5: Using Iterator Adaptors

#include <iostream>
#include <vector>
#include <iterator>
#include <algorithm>

int main() {
    std::vector<int> vec = {1, 2, 3, 4, 5};

    // Using back_insert_iterator
    std::vector<int> vec2;
    std::copy(vec.begin(), vec.end(), std::back_inserter(vec2));

    std::cout << "Vector after back insertion: ";
    for (int n : vec2) std::cout << n << " ";
    std::cout << std::endl;

    // Using front_insert_iterator
    std::vector<int> vec3;
    std::copy(vec.begin(), vec.end(), std::front_inserter(vec3));

    std::cout << "Vector after front insertion: ";
    for (int n : vec3) std::cout << n << " ";
    std::cout << std::endl;

    // Using insert_iterator
    std::vector<int> vec4 = {10, 20, 30};
    std::copy(vec.begin(), vec.end(), std::inserter(vec4, vec4.begin() + 2));

    std::cout << "Vector after insert: ";
    for (int n : vec4) std::cout << n << " ";
    std::cout << std::endl;

    return 0;
}

Explanation:

Additional Considerations

  1. Iterator Invalidation: Be aware that certain operations on containers can invalidate iterators.

  2. Performance: Different iterator categories have different performance characteristics. Random access iterators generally offer the best performance for algorithms.

  3. Const Correctness: Use const_iterator when you don't need to modify the elements being iterated over.

  4. Custom Iterators: When implementing custom iterators, ensure they conform to the expected behavior of their category.

  5. C++20 Concepts: With C++20, iterator concepts provide a more refined way to specify iterator requirements.

Summary

The <iterator> header in C++ provides essential tools for working with iterators:

Iterators are a fundamental concept in C++, bridging the gap between algorithms and containers. They provide a uniform way to access elements in different types of containers, enabling the writing of generic, reusable code. The <iterator> header is crucial for leveraging the full power of the STL and for implementing efficient, flexible data structures and algorithms.

Understanding and effectively using the facilities provided by <iterator> is essential for writing idiomatic, efficient C++ code, especially when working with the STL or implementing custom containers and algorithms. It's a key component in achieving the abstraction and genericity that C++ is known for in systems and application programming.

Related

Previous Page | Course Schedule | Course Content