5

I'm just learning STL and reverse_iterator has me confused. It has a default constructor but I don't understand how to use it. I tried:

reverse_iterator<int*> r{};
r --;

and the program crashed. I believe there is no point to this usage and it can easily cause a crash, so why is the default constructor allowed to be used?

Boann
  • 48,794
  • 16
  • 117
  • 146
wind2412
  • 1,011
  • 1
  • 9
  • 24
  • 2
    Probably just to support declaring "uninitialized" iterators to be assigned a specific value later. Just treat default-constructed iterators as uninitialized variables, i.e. don't do anything with them until you assign a meaningful value. – AnT stands with Russia Sep 17 '17 at 16:07
  • Why are you allowed to define a pointer that points to `nullptr` and then dereference it? There are lots of things that are allowed that are very unsafe, undefined even. It's what gives C++ it's speed and it's shoot-yourself-in-the-foot status. – Hatted Rooster Sep 17 '17 at 16:07
  • @RickAstley I believe the C++ standard library have moved from the "shoot feet at will" mentality to "you won't shoot your feet if it costs nothing". There would have to have further reasons if something unsafe were allowed – Passer By Sep 17 '17 at 16:08

2 Answers2

3

std::reverse_iterator are bidirectional iterators, which have a distinct requirement that they be default-constructible.

As to why bidirectional iterators are default-constructible, it is mostly because it is almost certain they are trivial to implement and giving guarantees like this makes algorithms easier to implement.

Writing things like int* p = nullptr; *p; is itself UB, it violates the precondition that p be dereferenceable, letting adaptors "adopt" these kinds of behaviour is rather natural.

Passer By
  • 19,325
  • 6
  • 49
  • 96
3

The documentation on cppreference says:

1) Default constructor. current is value-initialized. Operations on the resulting iterator have defined behavior if and only if the corresponding operations on a value-initialized Iterator also have defined behavior.

There are some iterators that are meaningful to be default constructed; usually not those that directly associated with containers (that I'm aware of). For example an istream iterator: http://en.cppreference.com/w/cpp/iterator/istream_iterator/istream_iterator. However, it's not bidirectional so you can't reverse it.

However, in principle, you could have an iterator that is both bidirectional, and whose default constructor/value initializer has at least some operations defined. For such an iterator, you'd want the behavior to be reflected through the reverse_iterator.

Nir Friedman
  • 17,108
  • 2
  • 44
  • 72