Converting an STL vector iterator to a raw pointer

Converting a std::vector<T>::iterator to a T* is harder than it should be; most obvious ways to do it either don't work at all or invoke undefined behavior (which often manifests as assertions when STL debugging is enabled).

C++:
  1. std::vector<T> v;
  2. std::vector<T>::iterator it;
  3.  
  4. T* p = v.empty() ? NULL : &v[0] + (it - v.begin());

Assumed: it is a valid iterator in v; it may be equal to v.end(); v may be empty.

According to the C++ standard, it's legal to have a pointer to the element just after the last element of an array, and it's legal to have an iterator referring to the element just after the last element of a vector, but dereferencing such pointers and iterators leads to undefined behavior.

Unfortunately, there is no way to convert from an iterator directly to a pointer without dereferencing the iterator (&it[0] and &*it both dereference the iterator). As a result, the only way to convert iterators to pointers that is able to handle all valid iterators requires having access to the vector in question.

Pretty much the only thing you can do with the end iterator is to compare it to another iterator (in the same vector) or subtract another iterator (in the same vector) from it.

Alas, &v[k] leads to undefined behavior if k is equal to v.size(), which means that &v[it - v.begin()] leads to undefined behavior if it is v.end(). Even though it's legal to have pointer to the element after the last one, it's not legal to obtain such a pointer by evaluating &v[v.size()].

The only way I found to get to the pointer corresponding to v.end() without invoking undefined behavior is &v[0] + v.size() -- assuming v is not empty. Thus, for a non-empty vector, &v[0] + (it - v.begin()) converts the iterator it to its matching pointer.

If the vector is empty, there is no guarantee that the storage for v is allocated, and &v[0] invokes undefined behavior, which is why we have to use NULL to cover the special case of the pointer to the beginning or the end of an empty vector.

File under: C++ code written to work around the fact that the code is written in C++.

Thanks to Mat Marcus for help.

Aug 6, 2006 in

5 Responses

  1. Scouring the net led me to this page, which perfectly explained what I was looking for and how to acheive what I need. Thanks!

  2. Eyal Itskovits

    I've came accross a oposite problem in which I had to convert from a raw pointer to a STL iterator.

    However, because you can USE raw pointer as random access iterator, I could do the following -

    BYTE *pPointer; std::vector myVec(pPointer, pPointer + bufferSize);

    And myVec.begin() will represent the pointer.

    Eyal.

  3. You should keep in mind that your code copies the buffer at pPointer into a vector. If you change the vector, memory at pPointer will not change, and vice versa.

  4. Philip Bliss

    I use &v.front() to get a pointer to the first element, which can be used to pass vectors to functions that expect dynamic arrays. The nice thing about that is that it automatically returns 0 for empty vectors, so no check is required.

    In the case of an empty vector, &v.front() + (it - v.begin()) would generate an invalid pointer, probably giving a segmentation fault, which is OK, since the behaviour of a dynamic array here would be to silently provide access to an incorrect memory address, possibly leading to memory corruption.

    For the pointer-past-the-end-of-the-vector, &v.back() + 1 seems like a good idea.

  5. Philip Bliss

    After doing slightly more research on this matter, I realized that v.front() is undefined for empty vectors--gcc seems to give a null pointer in that case, but the syntax &v.at(0) is preferable as it gives a defined result for empty vectors--an outofrange exception, which is useful for debugging.

    As for the one-past-the-end pointer, I suppose &v.at(v.size() - 1) + 1 would work, although it looks quite inelegant.

Leave a Comment

Please note: Comment moderation is enabled and may delay your comment. There is no need to resubmit your comment.