简体   繁体   中英

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.

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 only 1 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, eg “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.

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

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 (ie 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).

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM