Reputation: 4847
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
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
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
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
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: ifa
is dereferenceable,std::address_of(*a)
; otherwise, ifa
is reachable from a dereferenceable iteratorb
,std::pointer_from(b) + (a – b)
; otherwise a valid pointer value ([basic.compound]).
Upvotes: 7