Auto cast an iterator into its base pointer type ?

The Partridge Family were neither partridges nor a family. Discuss.
binbinhfr
Posts: 78
Joined: May 9th, 2019, 10:57 pm

Auto cast an iterator into its base pointer type ?

Post by binbinhfr » March 11th, 2020, 10:06 pm

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.

albinopapa
Posts: 4373
Joined: February 28th, 2013, 3:23 am
Location: Oklahoma, United States

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

Post by albinopapa » March 11th, 2020, 11:58 pm

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 ).
If you think paging some data from disk into RAM is slow, try paging it into a simian cerebrum over a pair of optical nerves. - gameprogrammingpatterns.com

binbinhfr
Posts: 78
Joined: May 9th, 2019, 10:57 pm

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

Post by binbinhfr » March 12th, 2020, 1:11 am

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* ?

albinopapa
Posts: 4373
Joined: February 28th, 2013, 3:23 am
Location: Oklahoma, United States

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

Post by albinopapa » March 14th, 2020, 5:40 am

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 )
If you think paging some data from disk into RAM is slow, try paging it into a simian cerebrum over a pair of optical nerves. - gameprogrammingpatterns.com

binbinhfr
Posts: 78
Joined: May 9th, 2019, 10:57 pm

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

Post by binbinhfr » March 14th, 2020, 8:39 am

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

Slidy
Posts: 80
Joined: September 9th, 2017, 1:19 pm

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

Post by Slidy » March 16th, 2020, 5:07 am

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.

User avatar
chili
Site Admin
Posts: 3948
Joined: December 31st, 2011, 4:53 pm
Location: Japan
Contact:

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

Post by chili » March 16th, 2020, 10:07 am

Slidy wanted to go to the Discord but clicked on the wrong link :kappa:

Good post tho
Chili

binbinhfr
Posts: 78
Joined: May 9th, 2019, 10:57 pm

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

Post by binbinhfr » March 17th, 2020, 9:16 pm

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

User avatar
chili
Site Admin
Posts: 3948
Joined: December 31st, 2011, 4:53 pm
Location: Japan
Contact:

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

Post by chili » March 19th, 2020, 12:20 am

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

albinopapa
Posts: 4373
Joined: February 28th, 2013, 3:23 am
Location: Oklahoma, United States

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

Post by albinopapa » March 19th, 2020, 7:08 am

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.
If you think paging some data from disk into RAM is slow, try paging it into a simian cerebrum over a pair of optical nerves. - gameprogrammingpatterns.com

Post Reply