pentadecagon
pentadecagon

Reputation: 4847

Convert vector iterator to pointer

Is there any way to convert a vector::iterator into a pointer without having access to the vector itself? This works only if the vector is available:

typedef vector<int> V;
int* to_pointer1( V& v, V::iterator t )
{
    return v.data() + (t-v.begin() );
}

But how can this be done without having the vector around? This wouldn't work:

int* to_pointer2( V::iterator t )
{
    // the obvious approach doesn't work for the end iterator
    return &*t;
}

In fact I would have expected this to be a very basic and popular question but for some reason I couldn't find it.

Upvotes: 14

Views: 9175

Answers (4)

Cheers and hth. - Alf
Cheers and hth. - Alf

Reputation: 145279

In general you are not guaranteed that there is a pointer corresponding to an iterator that refers to an ordinary vector item.

In particular std::vector<bool> is specialized so that &*it won't even compile.

However, for other vectors it's only1 the formally-pedantic that stops you from doing &*it also for the end iterator. In C99 it is, as I recall, formally valid to do &*p when p is an end pointer, and a goal of std::vector is to support all ordinary raw array notation. If I needed this I would just ignore the formal-pedantic, and write code with a view towards some future revision of the standard that would remove that imagined obstacle.

So, in practice, just do &*it. :)

#include <iostream>
#include <vector>
using namespace std;

auto main() -> int
{
    vector<int> x( 5 );
    cout << &*x.begin() << " " << &*x.end() << endl;
    cout << &*x.end() - &*x.begin() << endl;        // Works nicely IN PRACTICE.
}

But do remember that you can't do this for vector<bool>.


1) In a comment elsewhere user pentadecagon remarks: “Try -D_GLIBCXX_DEBUG, as documented here: gcc.gnu.org/onlinedocs/libstdc++/manual/debug_mode_using.html.” g++ often provides some means of bringing any formal UB to the front, e.g. “optimization” of formally UB loops. A solution in this particular case is simply to not ask it to do this, but more generally one may have to explicitly ask it to not do it.

Upvotes: 13

Walter
Walter

Reputation: 45434

I use this template:

template<typename It>
inline auto ptr(It const&it) -> decltype(std::addressof(*it))
{ return std::addressof(*it); }

In practice, this will work for most iterators. Exceptions are objects where either *it is not defined (vector<bool>::iterator) or where it points to nowhere (rather than to an past-the-last element). For your particular purpose, it shall be okay, except for vector<bool> (when the concept of a pointer is not sensible).

Upvotes: 0

utnapistim
utnapistim

Reputation: 27365

What you are asking is not possible for the end iterator; By definition, the end iterator points to a hypothetical element past the end of the array (i.e. de-referencing it, is always UB).

You said:

@Nick I want it to work for any valid iterator, including the end. It should be possible, because to_pointer1 also covers this case.

to_pointer1 doesn't cover this case. to_pointer1 returns an invalid memory address (Actually the address is probably valid, but there is no data there).

Upvotes: 1

ecatmur
ecatmur

Reputation: 157354

No, this is not currently possible. n3884 Contiguous Iterators: A Refinement of Random Access Iterators proposes a free function std::pointer_from which would satisfy your requirement:

Expression: std::pointer_from(a)
Return type: reference
Operational semantics: if a is dereferenceable, std::address_of(*a); otherwise, if a is reachable from a dereferenceable iterator b, std::pointer_from(b) + (a – b); otherwise a valid pointer value ([basic.compound]).

Upvotes: 7

Related Questions