I don't know the historical reason of this convention for iterators (including raw pointers and STL Iterators). But my opinion is it is consistent to the way we access arrays or containers with index.
1.
C/C++ array and C++ STL containers count the index from 0 to (size - 1).
Consider what will happen when you calculate the size of the array or container by taking the difference between a pair of pointers or iterators like:
size = ending_pointer - beginning_pointer;
// or
size = std::distance(beginning_iterator, ending_iterator);
This will really give you the size if ending_pointer or ending_iterator refers to the position past-the-last.
2.
Conventionally, looping through an array with index like this:
for (size_t i = 0 ; i < size ; ++i)
Note that we use less-than instead of less-than-or-equal-to.
For iterator:
// Usually found in implementations of STL algorithms
for (iterator_type it = beginning_iterator ; it != ending_iterator ; ++it)
Note that we use not-equal-to instead of equal-to.
3.
To handle the cases with an array or container of size 0, the convention of one-position-past-the-last is convenient for programmers and compiler optimization, since the beginning iterator will be equal to ending iterator.
for (iterator_type it = beginning_iterator ; it != ending_iterator_which_equals_the_beginning ; ++it)
// still consistent to
for (size_t i = 0 ; i < size_which_is_zero ; ++i)
As mentioned in others' answers, we prefer std::begin(container)
and std::end(container)
. They can free us from the troubles of pointer arithmetic and thus less error prone. They also make generic coding easier.