Converting a std::vector::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).
std::vector v;
std::vector::iterator it;
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.