Live data from Hacker News

Writing a custom iterator in modern C++

internalpointers.com

21–30 of 79 posts

Re: Writing a custom iterator in modern C++

#22
post #17

First sentence: “ An iterator is an object that points to an element inside a container” This is not the primary purpose of an iterator. Does anyone want to hazard a guess as to what an iterator’s primary purpose is? You? You? Bueller?

I think you are arguing that iterators are "primarily" for iteration. But in C++ they really are like an abstraction over C pointers. For example, you can hold a std::list::iterator, and use it to efficiently delete from a linked list, without ever iterating.

Sometimes C pointers are used for iteration, but I would not say that is their primary purpose.

Re: Writing a custom iterator in modern C++

#23

The classic iterator categories (input, output, ...) discussed in this article have been deprecated in C++20, and replaced with new concepts. I would expect a post from 2020 claiming to be about iterators "in modern C++" to be specifically about that change, but actually it's just about the legacy categories, so this is a pretty worthless article.

Honest question: what does it mean for something to be "deprecated" in (specifically) the c++ language spec?

The spec itself defines it as:

Normative for the current edition of the Standard, but having been identified as a candidate for removal from future revisions

This is a very blunt tool. In practice, a feature may be deprecated if it is:

1. Legacy inherited from C that serves no modern purpose. The register keyword.

2. Features hardly anybody implemented. Exported templates is the only example I am aware of. Like falling off the edge of the map.

3. Features that proved to be a bad idea, like incrementing a bool.

4. Features that proved to be wholly inadequate, like codecvt for dealing with Unicode.

5. Features that are reasonably new in C++ but obviated by new stuff. You don't need std::bind if you have lambdas.

This is my outsider's perspective; please chime in if you have standards committee insight.

Re: Writing a custom iterator in modern C++

#24
post #3

Earlier quoted context omitted.

> Isn't a random access iterator not an iterator? Why would it not be? It still allows you to iterate over an entire collection, however the order is left undefined so that certain performance characteristics can be exposed to the underlying implementation. This is the kind of tool you'd reach for if you don't care about the order of a collection, but you do care about performance, and probably care about the entire…

Random access iterators mean you can efficiently advance or retreat an iterator by an arbitrary amount. So a vector (via pointer arithmetic) but not a linked list.

Right but why should this matter at the type level? All you need to implement is next() and annotate it with documentation of the performance characteristics.

Re: Writing a custom iterator in modern C++

#25

There's six different kinds of iterator?! Off hand, is it just me or... - Isn't an iterator that outputs data to its recipient container not an iterator, but rather some type of filling API? - Isn't a random access iterator not an iterator but rather a slice view? - Isn't a contiguous iterator a leaky abstraction in that an iterator is just an interface that shouldn't expose how the data backing it is stored? This it…

[deleted]

Re: Writing a custom iterator in modern C++

#26

There's six different kinds of iterator?! Off hand, is it just me or... - Isn't an iterator that outputs data to its recipient container not an iterator, but rather some type of filling API? - Isn't a random access iterator not an iterator but rather a slice view? - Isn't a contiguous iterator a leaky abstraction in that an iterator is just an interface that shouldn't expose how the data backing it is stored? This it…

Iterators are inconsistent, but this plays to the strengths of C++'s duck-typed generics. The same code can either copy or insert, depending on whether you use std::begin or std::back_inserter; this isn't principled but it's powerful. The "six types of iterators" overstates it. You don't need to sweat those details unless you are writing boost or something. Just add what you need. I miss C++ iterators in other langua…

Backing up a utf8 stream is nontrivial though.

Re: Writing a custom iterator in modern C++

#27

Earlier quoted context omitted.

Random access iterators mean you can efficiently advance or retreat an iterator by an arbitrary amount. So a vector (via pointer arithmetic) but not a linked list.

Right but why should this matter at the type level? All you need to implement is next() and annotate it with documentation of the performance characteristics.

You can think of it as implementing `seek`, not just `next`.

`RandomAccessIterator` implements the `+=` and `-=` operations that `BidirectionalIterator` does not. Algorithms that accept `RandomAccessIterator` can then assume that calling += is possible.

Re: Writing a custom iterator in modern C++

#28

Earlier quoted context omitted.

Right but why should this matter at the type level? All you need to implement is next() and annotate it with documentation of the performance characteristics.

You can think of it as implementing `seek`, not just `next`. `RandomAccessIterator` implements the `+=` and `-=` operations that `BidirectionalIterator` does not. Algorithms that accept `RandomAccessIterator` can then assume that calling += is possible.

What's the advantage to using a random access iterator over a get() indexed? Like to me the point of an iterator is that it abstracts over access kind, and exposes the minimum viable view, which is sequential forward and possibly backward access.

If you want indexed access why wouldn't you just, you know, use anything that implements operator[]?

Re: Writing a custom iterator in modern C++

#29
post #17

First sentence: “ An iterator is an object that points to an element inside a container” This is not the primary purpose of an iterator. Does anyone want to hazard a guess as to what an iterator’s primary purpose is? You? You? Bueller?

The primary purpose of an iterator is to allow algorithms to be written in a generic manner without needing to know details about the type it's operating on. Since the algorithm only operates on the iterator type, any number of collections or other code that exposes that iterator type can be plugged into the same algorithm.

Take `std::copy_n` for example. You _could_ use this to copy from one vector to another:

    std::vector a = {1,2,3}, b = {0,0,0};
    std::copy_n(a.begin(), a.size(), b.begin());
But iterators also allow the input and output collection types to be different:

    std::vector a = {1,2,3};
    std::array b;
    std::copy_n(a.begin(), a.size(), b.begin());
Or even for the output to not be associated with a container at all.

    std::vector a = {1,2,3};
    std::copy_n(a.begin(), a.size(), std::ostream_iterator(std::cout, " "));

Re: Writing a custom iterator in modern C++

#30

Earlier quoted context omitted.

You can think of it as implementing `seek`, not just `next`. `RandomAccessIterator` implements the `+=` and `-=` operations that `BidirectionalIterator` does not. Algorithms that accept `RandomAccessIterator` can then assume that calling += is possible.

What's the advantage to using a random access iterator over a get() indexed? Like to me the point of an iterator is that it abstracts over access kind, and exposes the minimum viable view, which is sequential forward and possibly backward access. If you want indexed access why wouldn't you just, you know, use anything that implements operator[]?

Just that iterators is the API that C++ settled on for doing this in a generic way (well concepts in C++20, but I haven't learned that yet).

It's totally 100% kosher to write a function that calls `.at()` instead of `operator+=`. As long as it only needs to work on vectors, strings, or other stuff with a `.at()` method.

But if the function works on iterators instead it can work on ANY data structure that also fulfills the requirements of RandomAccessIterator API. String Views, raw pointers, a 3rd party Cord library, etc.

There's no inherent meaning to the iterator API requiring `operator+=` instead of something closer to `get()`, except that it means that the iterator itself doesn't need to know anything about container bounds (like I said above, raw pointers work as RandomAccessIterators).

Post reply on HN