Page 1 of 3

Auto cast an iterator into its base pointer type ?

Posted: March 11th, 2020, 10:06 pm
by binbinhfr
Hi there,

I have a problem with iterator and their supposed pointer equivalence...
I thought that an iterator was an intelligent pointer, pointing to the object it is supposed to describe.
But it seems that this pointer equivalence is not so obvious.

Look at the following code : I would like to be able to call the function f, passing by an iterator and it does not work directly...

Code: Select all

class T
{
public:
	int x;

	int get() { return(x); };
};

int read(T* t)
{
	return(t->x);
}

void Test()
{
	std::vector<T> vec = { {0},{2},{4} };

	for (auto i = vec.begin(), e = vec.end(); i != e; ++i)
	{
		std::cout << (*i).x << std::endl; // ok, iterator seems to be a T*
		std::cout << i->x << std::endl; // ok, iterator seems to be a T*
		std::cout << i->get() << std::endl; // ok, iterator seems to be a T*
		std::cout << read(i) << std::endl; // cannot cast iterator into T* !!!
		std::cout << read(&(*i)) << std::endl; // this trick works !!!
	}
}

What should I do ? Is the &(*i) trick the good solution ???

Thanks for your help.

Re: Auto cast an iterator into its base pointer type ?

Posted: March 11th, 2020, 11:58 pm
by albinopapa
Here's why the address of thing works.

First you are dereferencing the iterator which returns a T&, then you take the address of this T& and it becomes a T*.

Honestly, if you are going to pass a single object to a function, then just pass by reference:

int read(T& t) instead of int read(T* t)

If this read function is a part of another library and you can't change it, then you are kind of stuck using the &(*i) trick to dereference the iterator then take the address of the returned reference. There is a quicker/cleaner way to do what you are doing though.

Code: Select all

void Test()
{
	std::vector<T> vec = { {0},{2},{4} };

	for ( auto& i : vec )
	{
		std::cout << i.x << std::endl;
		std::cout << i.get() << std::endl;
		std::cout << read( &i ) << std::endl;
	}
}
The ranged for loop traverses the vector from beginning to end and hides all the iterator stuff. As long as you use <T>& or <T> const& ( where T is the type and not just your T class, or use auto& or auto const& ( const can come before or after 'auto' or the type name ).

Re: Auto cast an iterator into its base pointer type ?

Posted: March 12th, 2020, 1:11 am
by binbinhfr
wooo ! thanks for this very complete and clear answer. Using "by ref" helps a lot to clear things out, even if in this case I do not really understand why there is no more casting problem... Is it because of this new "for" presentation ? Why in my original post, the compiler cannot cast the iterator into a T* ?

Re: Auto cast an iterator into its base pointer type ?

Posted: March 14th, 2020, 5:40 am
by albinopapa
C++ is a strongly typed language, so for one, it tries to avoid implicit casts.

Also, an iterator is a type not a pointer or reference to type. You could do this though, but please don't:

Code: Select all

std::vector<T>::iterator it;
T* pT = reinterpret_cast<T*>( &it );
This is an explicit cast telling the compiler you seriously want to treat the address of the iterator as a T*.

In a ranged base for loop as I showed, each iterator is already dereferenced and the reference to the type is returned. The compiler basically does this behind your back:

Code: Select all

for( auto it = vec.begin(), end = vec.end(); it != end; std::advance( it ) )
{
     do_user_code( *it )
}
So instead of having you deal with the iterator, you deal with the element that the iterator would have held. This has been a feature since C++ 11 ( 2011 )

Re: Auto cast an iterator into its base pointer type ?

Posted: March 14th, 2020, 8:39 am
by binbinhfr
In a ranged base for loop as I showed, each iterator is already dereferenced and the reference to the type is returned. The compiler basically does this behind your back:
Yes, thanks, using this trick into my code, I finally understood this. But it's quite strange for me (I started coding with C 35 years ago, and programming is not my job) : if I remember well, I saw a chili's video where he told that this iterator were like "intelligent" pointers and that they were effectively "pointing" to the real data structure behind. So as a C programmer, I thought that the iterator-pointer equivalence/conversion was automatic...

Re: Auto cast an iterator into its base pointer type ?

Posted: March 16th, 2020, 5:07 am
by Slidy
The point of iterators is to look and feel like a pointer but they aren't always pointers. They "feel" like pointers because they overload the same operators that you would use with a real pointer (e.g. p->x, *p, ++p) but these are just function overloads and an iterator is it's own distinct class.

The reason iterators can't just be direct pointers is that that isn't applicable to all container types. Imagine a linked list container for example (std::list). With an iterator to one of the elements in the linked list, you'd expect to be able to call `++p` and go to the next element in the list, which doesn't match the behaviour you would get with a pointer.

Here's an example of an iterator that just simply wraps a pointer:

Code: Select all

class iterator
{
public:
  iterator( T* ptr ) : ptr( ptr ) {}

  T& operator*() { return *ptr; }
  const T& operator*() const { return *ptr; }
  T* operator->() { return ptr; }
  const T* operator->() { return ptr; }
  iterator& operator++() { ptr++; return *this; }
private:
  T* ptr;
};
For the dereference operator (*i) you can see it returns a reference to the underlying element. That's why you can convert an iterator to a pointer by doing this: &(*i)

Chili has a video where he covers iterators & there is also a homework where he gets you to make your own iterator for a stack class. I highly recommend you watch/do those if you haven't already.

Re: Auto cast an iterator into its base pointer type ?

Posted: March 16th, 2020, 10:07 am
by chili
Slidy wanted to go to the Discord but clicked on the wrong link :kappa:

Good post tho

Re: Auto cast an iterator into its base pointer type ?

Posted: March 17th, 2020, 9:16 pm
by binbinhfr
Chili has a video where he covers iterators & there is also a homework where he gets you to make your own iterator for a stack class. I highly recommend you watch/do those if you haven't already.
Oh yes, i do this very often. But when I try to do things by myself and try to escape from my old C habits, it's not always a success. The most annoying thing to me is the error message of the compiler. It often stops in the vector or list code with superlong cryptic messages and I often have problem to really understand the origin of my error...

Re: Auto cast an iterator into its base pointer type ?

Posted: March 19th, 2020, 12:20 am
by chili
That's just life man. Progress is found more in the failures than the successes. I will say that template errors are cancer. You learn to get better at reading them (and compiler diagnostics in general), but it's never something that you grow to like. Luckily, C++20 Concepts should make this area a whole lot less cancerous.

Re: Auto cast an iterator into its base pointer type ?

Posted: March 19th, 2020, 7:08 am
by albinopapa
try to escape from my old C habits, it's not always a success
I've tried helping someone break the C habit, it wasn't easy for them.