Setting pointer to object equal to iter?

Pages: 12
Alright, so here's the situation. I have a std::vector<Class>::iterator. I have a member of the same class type, that is a pointer. If I understand interators right, they are just pointers. So, could I just make that member equal to the iterator?

1
2
3
4
5
6
Enemy* target;
std::vector<Enemy>::iterator iter;

if(distance <= range)
           target = iter;
After a quick test, I can not do this. Any suggestions on how to accomplish what I'm going for here?

EDIT:
This works?
target = &(*iter);

This seems almost laughable to me but it worked. I'm not 100% sure why, or if this is the best option to go about doing this.
Last edited on
Why can't you just use the iterator?
closed account (zb0S216C)
The STL iterators are not convertible to their corresponding pointer types. Therefore, std::vector<int>::iterator is the type you're trying to assign, which of course, isn't going to happen. However, there's a workaround to this. On GCC, iterators have a secret member function called base() it obtains the internal pointer. Here's an example:

 
int *x_((std::vector<int>::iterator()).base());

On Microsoft's compiler, it's:

 
int *x_((std::vector<int>::iterator())._Ptr);

Wazzak
Iter is an iterator, not an Enemy pointer (I guess). Don't know much about it, but iterators seem a little more complex than just a pointer being incremented.

You deference the iterator to get the value: *iter, but then you still need to reference the memory location of the value &(*iter).
@framework,

Is there documentation on this hidden function anywhere? And I assume it's not a standard thing?

From readability, I'd say the way I ended up using is better. Is there a performance increase to using the base() function? I am going to be needing to do this operation pretty often.

EDIT:
http://www.cplusplus.com/reference/std/iterator/reverse_iterator/base/
Is this what you're talking about?
From what I'm reading, this doesn't sound like what you were talking about.
Last edited on
Why can't you just use the iterator?
Why can't you just use the iterator?


This is what I tried first. Didn't like converting over to that. I'll reproduce and post the build log.

EDIT: Log

\Tower.cpp:34: error: cannot convert '__gnu_cxx::__normal_iterator<Enemy*, std::vector<Enemy, std::allocator<Enemy> > >' to 'Enemy*' in assignment


From...

target = iter;
Last edited on
Using iterators will make them more coupled (to the container were they are).
If you will use vector I suggest to keep an index instead, as the iterators and pointers can be easy invalidated.

target = &(*iter);
An iterator is not a pointer. It's an structure used to traverse a container in a opaque way.
So when dereferencing an iterator you obtain the object, and then you get the memory address of the object. But the operations are not inverse of each other.

I guess that you could just
1
2
3
class vector{
public:
   typedef T* iterator;
but you could make it ``safer'' by using a wrapper instead.
I wasn't really wanting to use indices. Could I just set the initial capacity of the vector to a size large enough that it won't need to resize?

EDIT:
Well, after reading docs on it, looks like this will do exactly what I want.
Does seem to add just another thing that can cause an error down the road though.
Last edited on
closed account (zb0S216C)
ResidentBiscuit wrote:
"Is there documentation on this hidden function anywhere? And I assume it's not a standard thing? "

Not that I know of. I found the function by digging through the std::__normal_iterator implementation. I looked at its definition and the only thing it does is return the internal pointer. Since it's an in-line, one-liner function, it won't slow down the program, but it will increase the amount of CPU cache hits. Be wary, though, because too much in-lining can cause an increase in CPU cache misses, an increase in object code, and can cause thrashing.

Wazzak
Last edited on
Looks like it returns _Iterator _M_current, which I can't seem to find the initialization of. This code is definitely not recreational reading haha.

Anyway, the only thing that concerns me is the potential increased cache misses. Pretty much out of everything in the program, this would be the most performance dependent.

And the whole being compiler specific.
closed account (zb0S216C)
You could conditionally include code to match the compiler:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#if defined (MICROSOFT_COMPILER)
template <typename value_type>
value_type *base_of_iterator(const typename std::vector<value_type>::iterator iterator_)
{
    return(iterator_._Ptr);
}

#elif defined (GCC_COMPILER)
template <typename value_type>
value_type *base_of_iterator(const typename std::vector<value_type>::iterator iterator_)
{
    return(iterator_.base());
}
#endif

int main()
{
    std::vector<int>::iterator iterator_;
    int *pointer_(base_of_iterator<int>(iterator_));
}

Not the best thing in the world, but you get the idea.

Wazzak
int *pointer_(base_of_iterator<int>(iterator_));

Ok you've gone just past my knowledge here. What exactly is this doing?
closed account (zb0S216C)
It's a pointer declaration which is initialised with a call to base_of_pointer(). The type between base_of_pointer and the parentheses is used to deduce the type the iterator points to, because the compiler will not be able to deduce it. iterator_ is then passed to it.

Here's where the pre-processor directives come in. If MICROSOFT_COMPILER was defined, the _Ptr member of std::vector::iterator is returned. If GCC_COMPILER is defined, the base() member function of std::vector::iterator is called instead, and the pointer it returns, is returned from base_of_iterator().

Wazzak
Last edited on
int *pointer = (base_of_iterator<int>(iterator_));

Why can't you just do that?

And I understand template right (which I have barely messed with),

base_of_iterator<int>(iterator_) this is just a function call, with the <int> specifying the data type to be used, and iterator_ is the actual argument?
closed account (zb0S216C)
I guess you could initialise pointer in that way, but I pref the functional notation; personal preference, of course.

ResidentBiscuit wrote:
base_of_iterator<int>(iterator_) "this is just a function call, with the <int> specifying the data type to be used, and iterator_ is the actual argument?"

That's right. Note that iterator_ wasn't passed by reference because the underlying type is a primitive, and therefore, would likely incur a performance penalty.

Wazzak
Last edited on
Oooh I forgot all about assigning variables with functional notation. I remember seeing something for it a long time ago and brushed it off to the side as unimportant. Just looked it up and sparked my memory.

Now I thought with templates, you could just call the function normally, and the compiler would examine the arguments, and set a type accordingly?
closed account (zb0S216C)
Sometimes the compiler is able to deduce the type based on the arguments, but not in this case because std::vector::iterator is the parameter type, and int is the underlying type of the iterator class.

Wazzak
Ooh I get it. So it's just safe to explicitly state the data type for templates when you can?
Pages: 12