14

So when we need to traverse a container from start to end we write something like

for (i = v->begin(); i != v->end(); i++)

assuming i is an iterator for container v.

My question is "what guarantees that end will always point to one past the last element in container?" How does STL ensures this behavior and is there any chance that this case is not true?

3
  • 5
    The STL does not guarantee this behavior. The STL implements this behavior based on the requirements defined by the standard. The standard says this is how it is supposed to work the developer that implements the STL is then supposed to make the STL work correctly. Commented Sep 28, 2010 at 6:53
  • 6
    That's not best practice. Prefer the pre-increment operator ++i rather than i++ when you are not storing the value. For many types it is faster. Commented Sep 28, 2010 at 7:01
  • @Jive Dadson: that's not my main concern --> recomputing v->end() at each turn of the loop certainly is less efficient... for (auto it = v.begin(), end = v.end(); it != end; ++it) is the canonical form, though in C++0x one might as well use for (auto val : v) or std::foreach and a lambda function. Commented Sep 28, 2010 at 7:11

6 Answers 6

26

STL ensures this behavior by always storing stuff like this:

vector

In the end (pun), it doesn't matter what end() is, as long as it's always end() (and, obviously, can't be confused with any other node).

Sign up to request clarification or add additional context in comments.

2 Comments

Mate, you get +1 just for the funky graphics :-)
Doesn't the quote below from the C++ standard invalidate this answer? especially the graphic.
3

C++03 Section 23.1/7 says

begin() returns an iterator referring to the first element in the container.

end() returns an iterator which is the past-the-end value for the container.

If the container is empty, then begin() == end();

1 Comment

Is this the reason slist isn't officialy STL ? the end() of slist is 0
3

The stl specification guarantees that end will be one past the end See here. That will always be the case. Exactly how it does this can depend on the implementation (sometimes the values is just set to null for example), but rest assured your loop will be OK as long as v is a valid pointer.

Comments

2

"end will always point to one past the last element in container" means that if you increment iterator that points to the last element it will be equal to the result of end(). Implementation can be different. In Visual C++ std::vector::end() returns implementation specific iterator that holds zero pointer.

4 Comments

I strongly doubt it, as std::vector<T>::iterator is a random-access iterator. If std::vector<T>::end() returned (T*)0, end()-begin() would be illegal, yet it needs to return std::vector::size()
To be more correct: end returns implementation specific iterator that holds zero pointer.
The part of holding zero pointer is, well, unneeded and imprecise. In gcc vector implementation, vector<>::end() is defined as vector<>::begin()+vector<>::size(), and is actually stored in the vector<> object (GCC vector is implemented by means of three pointers: begin, end and end_of_capacity, where begin==end if the vector is empty, begin+size()==end at all times and end==end_of_capacity if size()==capacity(). There are no zero pointer anywhere to be seen.
@David Rodríguez, That was in "Implementation can be different." part of my answer. "zero pointer" is related to the Visual C++ implementation, not to gcc.
1

You're asking about all STL containers... not a word of mention of vector specifically where end() might be implemented as you obviously intuitively expect. What's one past the end in a std::map<>? The "end is one past the last used node" thing is just a logical concept, expressing that you can safely increment from that last-used node, differentiate/equate it from/to the abstract concept of "end", and do some node arithmetic where end is considered to be one further along than the last-used node. Don't take it too literally.

Comments

0

As some of the previous posters have stated end() is one past the end element. If you need to access the last element via iterators use iter = container.end() - 1; Otherwise, in the case of vectors, variable = someVector.back(); Assuming that variable is of the data type someVector contains.

In regard to what guarantees that it points to the end, the container itself handles that internally. You just have to treat it like a blackbox like any other object and trust it does it correctly.

Whenever the container is resized, it will track where the end is and will be up to date before you access end() again. Depending on the container however, if you have an iterator and alter it in some ways, it can invalidate the iterator and break your iteration process.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.