What is an iterator's default value?

For any STL container that I'm using, if I declare an iterator (of this particular container type) using the iterator's default constructor, what will the iterator be initialised to?

For example, I have:

std::list<void*> address_list;
std::list<void*>::iterator iter;

What will iter be initialised to?


Solution 1:

By convention a "NULL iterator" for containers, which is used to indicate no result, compares equal to the result of container.end().

 std::vector<X>::iterator iter = std::find(my_vec.begin(), my_vec.end(), x);
 if (iter == my_vec.end()) {
     //no result found; iter points to "nothing"
 }

However, since a default-constructed container iterator is not associated with any particular container, there is no good value it could take. Therefore it is just an uninitialized variable and the only legal operation to do with it is to assign a valid iterator to it.

 std::vector<X>::iterator iter;  //no particular value
 iter = some_vector.begin();  //iter is now usable

For other kinds of iterators this might not be true. E.g in case of istream_iterator, a default-constructed iterator represents (compares equal to) an istream_iterator which has reached the EOF of an input stream.

Solution 2:

The default constructor initializes an iterator to a singular value:

Iterators can also have singular values that are not associated with any sequence. [ Example: After the declaration of an uninitialized pointer x (as with int* x;), x must always be assumed to have a singular value of a pointer. — end example ]
Results of most expressions are undefined for singular values [24.2.1 §5]

Solution 3:

The iterator is not initialized, just as int x; declares an integer which isn't initialized. It does not have a properly defined value.

Solution 4:

An updated answer.

Up to and including C++11: a default- and value-initialized iterator may contain a singular value. Technically it may not be compared, nor dereferenced. See [iterator.requirements.general]/p5.

By convention however, STL implementations used to initialize such an iterator as a past-the-end iterator.

Starting from C++14: a value-initialized forward iterator compares equal to a past-the-end iterator. See [iterators.forward.iterators]/p2:

... value-initialized iterators may be compared and shall compare equal to other value-initialized iterators of the same type. [ Note: Value-initialized iterators behave as if they refer past the end of the same empty sequence.  — end note ]

Therefore:

std::list<void*>::iterator iter {}; should work as a past-the-end iterator.

std::list<void*>::iterator iter; is dangerous as iter will be initialized only if one has a non-trivial default constructor. Though for std::list that will probably be the case, and so should also work.