Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is an iterator in general?

Tags:

c++

iterator

This problem comes up when I tried to write a C++ class template with ctor that accept "general iterator". I don't know if it's appropriate to use the word general here, but what I mean is that it can accept iterator just like STL container.

In other word, I'm confused about iterator. It seems that all STL container has the same type iterator, so what's that type? Is it just pointer? Or something more complicated? But STL container do accept normal pointer.

(I would like to compare it to Iterator<T> in Java, which is quite simple and it's just a class)

like image 783
Ziqi Liu Avatar asked Jul 30 '18 03:07

Ziqi Liu


People also ask

What is meant by iterator?

An iterator is an object that contains a countable number of values. An iterator is an object that can be iterated upon, meaning that you can traverse through all the values. Technically, in Python, an iterator is an object which implements the iterator protocol, which consist of the methods __iter__() and __next__() .

What is the main use of iterators?

The primary purpose of an iterator is to allow a user to process every element of a container while isolating the user from the internal structure of the container. This allows the container to store elements in any manner it wishes while allowing the user to treat it as if it were a simple sequence or list.

What is an iterator What are types of iterators?

An iterator is an object that can iterate over elements in a C++ Standard Library container and provide access to individual elements.

What is an iterator in vector?

Vector's iterators are random access iterators which means they look and feel like plain pointers. You can access the nth element by adding n to the iterator returned from the container's begin() method, or you can use operator [] . std::vector<int> vec(10); std::vector<int>::iterator it = vec.


2 Answers

In C++ an Iterator is a concept, not a concrete (or abstract) type, but any type that obeys certain iterator like rules.

For example iterators generally can be incremented ++i. They can be accessed (dereferenced) *i to obtain the value they currently point to. They are essentially abstractions of a pointer.

In the Standard Library's containers & algorithms there are different kinds of iterators with different properties. Their properties are listed here:

https://en.cppreference.com/w/cpp/iterator

So when writing algorithms in C++ that accept iterators, generally just accept generic template parameters and use the appropriate iterator properties in the function. The compiler will complain if the user passes something to your function that doesn't obey the iterator rules:

template<typename Iterator>
void my_algorithm(Iterator begin, Iterator end)
{
    for(; begin != end; ++begin)
        std::cout << *begin << '\n';
}

You can add a whole bunch of specific checks to make sure the user passed something sensible, but that's too broad for this question.

Note:

Whilst currently concepts, such as Iterator, are merely a set of agreed upon semantic properties in the Standard that programmers must follow, a more comprehensive solution that will formalize such concepts (in code) is intended for the next version of the Standard, C++20.

like image 95
Galik Avatar answered Oct 25 '22 04:10

Galik


Iterators as a concept come from before C++ was a standard.

C++ started out as C with classes. More features where added, and an exponentially growing number of people got interested in the language.

One very important bit of work was called the STL -- the Standard Template Library -- originally written by Stepanov and Lee. in 1994 at Hewlett-Packard, later maintained by SGI.

This library used the template metaprogramming part of C++ in quite revolutionary ways. It was written to permit near bare-metal performance with abstracted types, with algorithm implementations divorced from container implementations, for nearly arbitrary types.

Iterators are a Concept -- a higher kind of type

In it, the iterator was a concept. A concept in C++ is a category of types (a type of types you could say). Concepts in C++ are not enforced by the compiler (at this time).

A type satisfies a concept if it has the required operations, and those operations respect the rules of the concept.

There is a heirarchy of concepts around iterators in the STL and later in the C++ standard. They go from the least restrictive (an iterator) to the most (a read-write random access contiguous iterator), and form a tree.

Template functions write functions

When a template algorithm asks for an Iterator, they are asking for a type that satisfies the Iterator concept (as described in the C++ standard). When they ask for a RandomAccessIterator, they are asking for a type that satisifies the RandomAccessIterator concept (which also includes the Iterator concept, the ForwardIterator concept, and a few others).

So template<class ForwardIterator> void std::sort( ForwardIterator, ForwardIterator ) is a template function that takes two instances of the same type which satisfy the ForwardIterator concept.

ForwardIterators have to support a number of operations (*it, ++it, bool b = it != it, bool b = it == it, etc), suport certain traits (iterator_traits<it>::iterator_category, iterator_traits<it>::reference, iterator_traits<it>::value_type, etc), and those operations have to follow certain rules.

If you feed it a type that satisfies RandomAccessIterator, std::sort guarantees better performance than if passed a ForwardIterator.

A raw pointer satisfies both Forward RandomAccess iterator without you doing anything. std::vector<?>::iterator also satisifes both, but often isn't a raw pointer (the std library did some work).

The two types -- the raw pointer, and std::vector<?>::iterator -- are usually unrelated types. C++'s template and traits system permits unrelated types to be understood by the same template algorithm with zero runtime overhead.

In c++2a there are plans to introduce in-language Concepts that actually check some of the requirements for things like RandomAccessIterator, and document in-langauge the other requirements that cannot practically be checked.

C++ is not an OO-language

You are possibly confused by being used to object oriented languages. C++ supports object oriented programming, but is not an object oriented language. It supports polymorphism -- treating multiple types the same -- without object based inheritance in a number of ways.

In an object oriented language, every iterator would inherit from an abstract iterator type. Algorithms would interact with the iterator via that abstract interface, often dispatching calls via a virtual function table of some kind. Values of the type wouldn't be possible, as the algorithm code would be compiled without knowing how many bytes the iterators take up, so extra indirection would occur.

In C++, the algorithm isn't a function until you pass it the type of the iterator. At that point, the function is custom-written for that iterator. The C++ standard states that if the iterator does certain things (obeys the Concept required), that the function written by the template will have certain behavior.

This template-written function knows how big the iterator is, what the operations do, can inline the operations and store instances of the iterator in buffers or on the stack as a value. Unless the iterator forces it, there is no virtual dispatch, and if the operations are visible, they can be inlined into the written function.

Tight loops can be examined by the compiler and vectorization can occur, just as if you wrote the function by hand.

The same template can sort database entries or strings or integers; each case a new function is written, and the compiler is told to try to make it go faster.

TL;DR

Iterators are not a type; they are a kind of type. Completely unrelated types can both be iterators. There is no base class for iterators; there is just certain ways they guarantee they behave.

C++ algorithms generates custom code for each type of iterator you pass to std::sort; if you sort a vector of int and a vector of strings, no binary code is shared between the two (except the possibility of comdat folding).

The concepts (kind of type) Iterator/ForwardIterator/RandomAccessIterator are documented requirements on the types passed to the C++ algorithms. No enforcing is done, other than that the compiler is free to do literally anything if you fail to meet the requirements.

like image 8
Yakk - Adam Nevraumont Avatar answered Oct 25 '22 06:10

Yakk - Adam Nevraumont