Defining iterator of my own container
I am confus开发者_运维百科ed with some concepts about defining my own iterator:
From this: http://www.cs.northwestern.edu/~riesbeck/programming/c++/stl-iterator-define.html, which seems to suggest using inner iterator class which defines the operators. Many others inherit the base class iterator
to redefine the operators.
I am quite confused about which methods should be used. Why is there
typedef ptrdiff_t difference_type;
for example, at the beginning of the definition of container class?
Thank you very much!
The C++ specification on what exactly an STL container is mandates that any STL container type have several different fields available. Some, like begin()
and end()
, are functions, while others, like iterator
, are types. These restrictions also apply to iterators. This allows C++ template functions to introspect on their types of their arguments to look up more properties. For example, all STL iterator types must define an iterator_category
field containing a type encoding their capabilities. This way, the STL algorithms can have different implementations of different functions based on the power of the iterators they accept. A class example is the distance
function, which takes two iterators and returns the number of spaces between them. If the input is a lowly ForwardIterator
or BidirectionalIterator
this works by marching the iterators forward and counting how many steps were took, which runs in O(n). If the input is a RandomAccessIterator
, then the iterators can just be subtracted to get the result in O(1).
Prior to C++17, the recommendation was to include the <iterator>
header and inherit from std::iterator
to automatically generate the necessary nested types you’d need (reference
, pointer
, etc.). That type is now deprecated, and so you’ll need to manually either add typedef
s or specialize std::iterator_traits
to export this information.
As for what operators you need to overload, at a bare minimum you need to get ++
(prefix and postfix), ==
, !=
, *
(pointer dereference), and ->
defined. All iterator types support this. For bidirectional iterators or higher, you should also have --
defined (prefix and postfix). Finally, for random-access iterators, you should support []
, +
, +=
, -
(back up many steps and subtract two iterators), -=
, <
, >
, <=
, and >=
.
Hope this helps!
Although @templattypedef's answer is accurate, perhaps I can clarify the situation a little bit.
An iterator is typically defined as a nested class inside the container. std::iterator
is typically used as a base class to make it easier for you to define your iterator class. You never really have to use std::iterator
-- it's just there to make the job a bit easier and (especially) reduce the amount of code you need to type. In fact, std::iterator
is officially deprecated, so using it is discouraged. It might someday be removed from the standard (though I don't know of any concrete date when it's likely to be removed).
Oh, and for reasons that have no bearing on the question at hand, it's sometimes preferable for an iterator to be defined outside the container class being iterated. When the iterator class definition is nested in the container definition, the iterator depends on all the template parameters of the surrounding class. That's rarely necessary or desirable though. For example, two vectors with different allocators can still normally have the same iterator type--changing the allocator doesn't change iteration.
Although using std::iterator
may help with typedef
s, it certainly doesn't help with the actual implementation.
The Boost.Iterator library has lots of good things for this, and I'll suggest to read about the boost::iterator_adaptor which greatly reduce the amount of code you need to type to define a new iterator on top of an old one.
精彩评论