Izzo
Izzo

Reputation: 4928

How do you use std::distance to find the array index of a pointer to an std::array element?

Let's say I have a std::array of some object and create a pointer to one of the objects.

std::array<Object, 100> my_array;

Object* ptr_object = &my_array[50]; 

So assuming I don't know the index referred to by ptr_object, how would I go about and back-track to find this index in C++11?

I've come across some readings that suggest std::distance might help, however, my attempt of

std::distance(my_array, ptr_object);

throws an error stating that "no matching overloaded function found".

Upvotes: 2

Views: 4378

Answers (2)

AnT stands with Russia
AnT stands with Russia

Reputation: 320551

I would advise against gratuitous use of std::distance, unless it is a requirement in your case.

std::distance is an interface-unifying function, whose purpose is to allow one to calculate distances between various kinds of iterators: random-access, bidirectional, forward etc. This function is intended to conceal the inefficiency of directly calculating the distance for non-random-access iterators, in situations where you really know what you are doing and really want to accept that inefficiency. It is intended to stand out in your code (like a cast), signalling the fact that in general case the code might be inefficient, but you are willing to accept that at least for now, like in temporary "sketch" code. (The same applies to std::advance).

If you do not intend to "hide" the inefficiency, i.e. you intend your code to work with random-access iterators only, don't use std::distance. Just subtract the iterators

std::ptrdiff_t i = ptr_object - my_array.data();

Upvotes: 5

Remy Lebeau
Remy Lebeau

Reputation: 596673

The easiest way to get the index is to use pointer arithmetic. Simply subtract a pointer to the desired element from a pointer to the first element, eg:

size_t index = (ptr_object - my_array.data()/*&my_array[0]*/);

std::distance() takes iterators as input, and raw pointers can be used as iterators. So, you can use a pointer to the first element as the starting iterator, and a pointer to the desired element as the ending iterator, eg:

size_t index = std::distance(my_array.data()/*&my_array[0]*/, ptr_object);

Note how this differs from your code, where you try to pass the std::array itself to std::distance(). That does not work.

Both of the above have constant complexity, since they are simple arithmetic operations (std::distance() is optimized for random-access iterators, like raw pointers and std::array iterators).

Alternatively, you can use actual iterators instead, but that requires iterating through the array to get an iterator to the desired element without knowing its index beforehand, eg:

auto iter = std::find_if(std::begin(my_array), std::end(my_array), [=](Object &o) { return (&o == ptr_object); });
size_t index = std::distance(my_array.begin(), iter);

Upvotes: 6

Related Questions