Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can/Should I inherit from an STL iterator?

Tags:

c++

iterator

stl

Can/Should i inherit from STL iterator to implement my own iterator class? If no, why not?

like image 397
Fausto Carvalho Marques Silva Avatar asked Jun 24 '11 16:06

Fausto Carvalho Marques Silva


People also ask

What is an iterator in STL?

An iterator is used to point to the memory address of the STL container classes. For better understanding, you can relate them with a pointer, to some extent. Iterators act as a bridge that connects algorithms to STL containers and allows the modifications of the data present inside the container.

Does STL stack have iterator?

Stack does not have iterators, by definition of stack. If you need stack with iterators, you'll need to implement it yourself on top of other container (std::list, std::vector, etc).


1 Answers

Short answer

Many consider that the class std::iterator does not offer much compared to regular type aliases, and even obfuscates them a bit by not explicitly providing the names and relying on the order of the template parameters instead. It is deprecated in C++17 and is likely to be gone in a few years.

This means that you shouldn't use std::iterator anymore. You can read the whole post below if you're interested in the full story (there's a bit of redundancy since it has been started before the deprecation proposal).


Legacy answer

You can ignore everything below if you're not interested in history. The following fragments even contradict themselves several times.

As of today (C++11/C++14), the standard seems to imply that it isn't a good idea anymore to inherit from std::iterator to implement custom iterators. Here is a brief explanation, from N3931:

Although the Standard has made this mistake almost a dozen times, I recommend not depicting directory_iterator and recursive_directory_iterator as deriving from std::iterator, since that's a binding requirement on implementations. Instead they should be depicted as having the appropriate typedefs, and leave it up to implementers to decide how to provide them. (The difference is observable to users with is_base_of, not that they should be asking that question.)

[2014-02-08 Daniel comments and provides wording]

This issue is basically similar to the kind of solution that had been used to remove the requirement to derive from unary_function and friends as described by N3198 and I'm strongly in favour to follow that spirit here as well. I'd like to add that basically all "newer" iterator types (such as the regex related iterator) don't derive from std::iterator either.

The paper cites N3198 which itself states that it follows the deprecation discussed in N3145. The reasons for deprecating the classes that only exist to provide typedefs are given as such:

Our experience with concepts gives us confidence that it is rarely necessary to depend on specific base class-derived class relations, if availability of types and functions is sufficient. The new language tools allow us even in the absence of language-supported concepts to deduce the existence of typenames in class types, which would introduce a much weaker coupling among them. Another advantage of replacing inheritance by associated types is the fact, that this will reduce the number of cases, where ambiguities arise: This can easily happen, if a type would inherit both from unary_function and binary_function (This makes sense, if a functor is both an unary and a binary function object).

tl;dr: classes which only provide typedefs are now deemed useless. Moreover, they increase coupling when it is not needed, are more verbose, and can have unwanted side effects in some corner cases (see the previous quotation).


Update: issue 2438 from N4245 seems to actually contradict what I asserted earlier:

For LWG convenience, nine STL iterators are depicted as deriving from std::iterator to get their iterator_category/etc. typedefs. Unfortunately (and unintentionally), this also mandates the inheritance, which is observable (not just through is_base_of, but also overload resolution). This is unfortunate because it confuses users, who can be misled into thinking that their own iterators must derive from std::iterator, or that overloading functions to take std::iterator is somehow meaningful. This is also unintentional because the STL's most important iterators, the container iterators, aren't required to derive from std::iterator. (Some are even allowed to be raw pointers.) Finally, this unnecessarily constrains implementers, who may not want to derive from std::iterator. (For example, to simplify debugger views.)

To sum up, I was wrong, @aschepler was right: it can be used, but it is certainely not required - it isn't discouraged either. The whole "let's remove std::iterator" thing exists for the standard not to constrain the standard library implementers.


Round 3: P0174R0 proposes to deprecate std::iterator for a possible removal in the future. The proposal is already pretty good at explaining why it should be deprecated, so here we go:

The long sequence of void arguments is much less clear to the reader than simply providing the expected typedefs in the class definition itself, which is the approach taken by the current working draft, following the pattern set in C++14 where we deprecated the derivation throughout the library of functors from unary_function and binary_function.

In addition to the reduced clarity, the iterator template also lays a trap for the unwary, as in typical usage it will be a dependent base class, which means it will not be looking into during name lookup from within the class or its member functions. This leads to surprised users trying to understand why the following simple usage does not work:

#include <iterator>  template <typename T> struct MyIterator : std::iterator<std::random_access_iterator_tag, T> {    value_type data;  // Error: value_type is not found by name lookup      // ... implementations details elided ... }; 

The reason of clarity alone was sufficient to persuade the LWG to update the standard library specification to no longer mandate the standard iterator adapators as deriving from std::iterator, so there is no further use of this template within the standard itself. Therefore, it looks like a strong candidate for deprecation.

This is becoming a bit tiring and not everyone seems to agree, so I will let you draw your own conclusions. If the committee eventually decides that std::iterator should be deprecated, then it will make it pretty clear that you shouldn't use it anymore. Note that the follow-up paper highlights a great support for the removal of std::iterator:

Update from Jacksonville, 2016:

Poll: Deprecate iterator for C++17??
SF  F   N   A   SA
6    10  1    0   0

In the above poll results, SF, F, N, A and SA stand for Strongly For, For, Neutral, Against and Strongly Against.

Update from Oulu, 2016:

Poll: Still want to deprecate std::iterator?
SF F N A SA
3   6  3  2  0

P0619R1 proposes to remove std::iterator, possibly as soon as C++20, and also proposes to enhance std::iterator_traits so that it can automatically deduce the types difference_type, pointer and reference the way std::iterator does when they're not explicitly provided.

like image 68
Morwenn Avatar answered Sep 19 '22 23:09

Morwenn