Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Convert vector iterator to pointer

Tags:

c++

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.

like image 676
pentadecagon Avatar asked Jun 18 '14 08:06

pentadecagon


2 Answers

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.

like image 119
Cheers and hth. - Alf Avatar answered Sep 20 '22 16:09

Cheers and hth. - Alf


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]).

like image 35
ecatmur Avatar answered Sep 20 '22 16:09

ecatmur