2

While iterating through a std::map or std::vector or any container which has iterator in it, is checked against the variable.end() and not something like container<>::end. For example,

map<int, int> var;
for(map<int, int>::iterator it = var.begin(); it != var.end(); it++)
...                                           ^^^^^^^^^^^^^^^

Can't above highlighted part be something like:

it != map<int,int>::end

which is similar to static member string::npos. What can be the reason behind the design decision for providing .end() on per variable bases and not on the per type of container bases ? (i.e. map<int,int>::end and map<int,double>::end would be different; but for every map<int,int> variable, the ::end will be similar.)

iammilind
  • 68,093
  • 33
  • 169
  • 336
  • 3
    Wouldn't it be annoyingly inconsistent for `begin()` to be an instance method, but `end` be a static member? What about `rbegin()` and `rend()`? – Greg Hewgill Jan 09 '12 at 06:21
  • 1
    This question makes no sense. Do you have a specific case where this would be beneficial? – Pubby Jan 09 '12 at 06:25
  • 1
    @Pubby, in some applications we can directly compare the `end` with a return value of a function. In such cases we won't need a variable name which can be local to function. – iammilind Jan 09 '12 at 07:20

3 Answers3

7

This way, some array-based containers could implement an iterator simply as a pointer to an element. The one-past-the-last-element pointer is different for every array.

ibid
  • 3,891
  • 22
  • 17
  • I guess this is the only true answer. Backward compatibility with simple container implementations. – Spidey Jul 04 '12 at 13:09
5

Consider the following two arrays:

int a1[] = {2, 3, 4};
int a2[] = {5, 6, 7};

One past the last element of the 2 arrays are different:

int *p1 = a1 + 3; // for a1
int *p2 = a2 + 3; // for a2

You can't use one pointer for the other. There is no universal constant to represent end-of-array. The following is wrong:

for (int *p = a1; p != a2; p++)

The explanation of not having same end() for same kind of container's iterator is similar.

Donotalo
  • 12,748
  • 25
  • 83
  • 121
4

Iterators are for iterating, moving forward and backward. They need to provide increment and decrement (bidirectional iterators) operations. When you decrement an end() iterator, you get to the last item in the container. This allows iterating backwards.

As to your suggestion. Implementing this would mean that each iterator carries the end iterator with it, and compares equal to the static end iterator when it is equal to the real end iterator it is storing. There would actually be no point to make all the static end iterators different types, because that "iterator" cannot be used for anything other than that anyway.

A design like that would simply be more cumbersome to implement and more wasteful to use. If each iterator has to know the end of its container, then to designate an arbitrary range, you'd have to add two potentially unused iterators to the end in the mix.

UncleBens
  • 40,819
  • 6
  • 57
  • 90