How do you use a C++ iterator? - c++

I have a vector like so:
vector<MyType*> _types;
And I want to iterate over the vector and call a function on each of MyTypes in the vector, but I'm getting invalid return errors from the compiler. It appears the pos iterator isn't a pointer to MyType, it's something else. What am I not understanding?
Edit: Some code..
for (pos = _types.begin(); pos < _types.end(); pos++)
{
InternalType* inst = *pos->GetInternalType();
}
The compiler errors are:
invalid return type 'InternalType**' for overloaded 'operator ->'
'GetInternalType' : is not a member of 'std::_Vector_iterator<_Ty,_Alloc>'
Edit pt2
Should my vector contain pointers or objects? What are the pros and cons? If I am using new to create an instance, I am guessing I can only use a vector of pointers to MyType is that correct?

If the vector contained objects, not pointers, you could do pos->foo(). The iterator "acts like" a pointer. But your vector contains pointers, so an iterator will act like a pointer to a pointer, so needs to be dereferenced twice.
MyType *pMyType = *pos; // first dereference
if (pMyType) { // make sure the pointer is not null
pMyType->foo(); // second dereference
}
If you are sure the pointer is not null, you could do this:
(*pos)->foo();
The parenthesis around *pos are needed so the dereference applies to pos, not to pos->foo(). Order of operations.
If your vector needs to contain items from a class hierarchy (e.g., subclasses of MyType), then you have to make it a vector of pointers. Otherwise a vector of objects is probably simpler.

You've defined _types as a vector of pointers. Assuming your pos is an iterator into that vector, it's going to be an iterator to a pointer, so you'll need to dereference it twice to get to an instance of MyType.
Edit: based on what you've added to the question: You have something like *pos->whatever. Try (*pos)->whatever instead. As it stands, you're trying to use whatever as a member of the iterator, then dereference the result...

Iterators are not pointers. Iterators are types that behave like pointers. In some implementations of some containers, the iterator type may in fact be a pointer (all pointers are iterators), but this cannot be used as a general rule.
If you need to generate a pointer from an iterator, you can use &*pos, which will dereference the iterator and then get the address of the result (of course, this doesn't work if unary operator & is overloaded, but that's a whole other can of worms).

for (vector<MyType*>::iterator i = _tpes.begin(); i != _types.end(); ++i) {
// do something with i
}

for (vector<MyType*>::iterator it = _types.begin();
it != _types.end();
++it)
{
// `*it` is this iteration's `MyType*` from your vector
}

Related

why not we pass asterisk(*) in iterator in stl

When we use iterator we declare iterator and then itr as an object, but we don't pass any pointer like we do every time when declaring pointer variable but when we print the value of vector by the use of iterator than how itr became*itr
when we doesn't pass any pointer
Is pointer is hidden or its work on the background?
Example like:
iterator itr;
*itr
How it works does * means any other things to iterator or *itr act like normal pointer variable.
If it works like a pointer variable then why we do not pass * when declaring itr.
An iterator is an object that lets you travel (or iterate) over each object in a collection or stream. It is a sort of generalization of pointers. That is, pointers are one example of an iterator.
Iterators implement concepts required by various algorithms such as forward iteration (meaning it can be incremented to move forward in the collection), bi-directional iteration (meaning it can go forward and backward), and random access (meaning you can use an index an arbitrary item in the collection).
For instance, moving backward can't typically happen in a stream, so stream's iterators are typically forward iterators only because once you access a value, you can't go back in the stream. A linked list's iterators are bi-directional because you can move forward or backward, but you cannot access them by indexing because the nodes are not typically in contiguous memory, so you can't calculate with an index where an arbitrary element is. A vector's iterators are random access and very much like pointers. (C++20 made these categories more precise, so the old categories are now called "Legacy".)
Iterators can also have special functions, such as std::back_inserter, which appends items to the end of a container when a value is assigned to it's referrent.
So, you can see that iterators allow you to be more precise in defining what your consumer of iterators expects. If your algorithm requires bi-directional iteration, you can communicate that and limit it so it won't work with forward-only iterators.
As for the * operator, it is similar to the * operator for a pointer. In both cases, it means, "give me the value referred to by this handle". It is implemented via operator overloading. You do not need the * when declaring an iterator because it is not a pointer, which is a lower-level construct in the language. Rather, it is an object with pointer-like semantics.
To answer your questions below:
No, the * is not automatically created. When you declare an iterator you are declaring an object. When the class for that object is defined, it may or may not have an operator overload for the * operator (or the == or the + or any other operators).
When you go to use the object, such as passing it to a function, the types will need to match up. If a function you were passing it to requires an iterator (e.g. std::sort()), then no dereferencing * is needed. If the function was expecting a value of the type the iterator refers to, then you would need to dereference it first. In that case the compiler calls the overloaded operator *and returns the value.
That is the nature of overloaded operators -- they look like ordinary operators but ultimately are resolved to a function call defined by the creator of the class. It works the same as if you defined a matrix class that has plus and minus operators overloaded.
How it works does * means any other things to iterator or *itr act like normal pointer variable.
It depends what type stands behind iterator. It can be alias for a pointer:
using iterator = int *;
iterator itr;
*itr; // it is pointer dereferencing in this case.
Or it can be a user defined type:
struct iterator {
int &operator*();
};
iterator itr;
*itr; // it means itr.operator*() here
So without knowing what type iterator is it is quite impossible to say what * actually does here. But in reality you should not care as developers of the library should implement it the way it would not matter for you.

Pointer to nth element in a vector of list

I need to return a pointer to some value in my list
std::vector<std::list<int>> lists;
...
if(lists.at(i).front()==val){
//return a pointer after the first value
return ptr;
}
The best way i can think of is using std::next, but i have no idea how to make it returns a pointer
The best way i can think of is using std::next, but i have no idea how to make it returns a pointer
std::next returns an iterator. You can use the indirection operator to get the pointed object. You can use the addressof operator to get the memory address (i.e. a pointer) of that object. So:
auto it = whatever; // iterator to the object whose pointer you want
return &*it; // return the pointer
Not relevant to int, but for some rare cases, you may need to use std::addressof in case the the type has an overloaded addressof operator.
Also, I recommend considering whether it makes any sense to return a pointer rather than the iterator itself.
I think of a function like this:
std::list<int>::iterator get(std::vector<std::list<int>>& lists, int i,int val)
{
assert(i<lists.size());
if(lists.at(i).front()==val)
{
//return a pointer after the first value
std::list<int>::iterator it = lists.at(i).begin();
return it++;
}
return lists.at(i).end();
}
Iterators are just "better" pointers. That is, you can use them as pointers (access value by dereferencing them)
auto it = lists.at(i).begin() // returns iterator to first element in i-th list in vector
...
*it // you can access value as if "it" was pointer
it++; // iterators can be "moved", that is, they will point to next element than before
if you really wish to return pointer type *int, instead of std::list<int>::iterator, you dereference it and gain reference back again
return &(*it);
for more on iterators, you can look here. You can see that there are many types of iterators, but all can be dereference as if they were pointers.
std::list<>:iterator is bidirectional iterator (they don't have random access, but you can move them by one element at a time, forward or backward)

Cannot cast list iterator to an object

I get the error:
error C2682: cannot use 'dynamic_cast' to convert from 'std::_List_iterator<_Mylist>' to 'UserBean *'
When executing:
list<UserBean> * userBeans = getUserBeans();
for(list<UserBean>::iterator i = userBeans->begin(); i != userBeans->end(); i++)
UserBean * newUser = dynamic_cast<UserBean*>(i);
Am I doing something wrong, or can you not convert iterator items to objects?
Sometimes iterators are implemented as raw pointers to container items, but more times than not, they are not pointers at all, so don't treat them that way. The correct way to access the item that an iterator refers to is to dereference the iterator, eg:
UserBean &newUser = *i;
Or:
UserBean *newUser = &(*i);
Iterators usually override the -> operator so you can access members of the referenced item, in cases where the iterator refers to an actual object instance (which yours does) and not a pointer to an object instance, eg:
i->SomeMemberHere
Am I doing something wrong, or can you not convert iterator items to objects?
No, you can't. You can dereference iterators to access objects:
UserBean & newUser = *i;
You can't convert an iterator to a pointer like this - that's not what dynamic_cast is for. You should only be using dynamic_cast when you're dealing with polymorphic behaviour (if at all). You can, however, do it like so:
UserBean* newUser = &*i;
This dereferences the iterator to get the object and then takes the address of the object.
The type of your container is list<UserBean> not list<*UserBean>
That's why your iterator is wrong. Its type is UserBean. Not UserBean*.
UserBean userBean = *i;
or
UserBean& userBean = *i;

why can't I dereference an iterator?

If I have a vector of objects (plain objects, not pointers or references), why can't I do this?
Object* object;
object = vectorOfObjects.end();
or
object = &vectorOfObjects.end();
or
object = &(*vectorOfObjects.end());
also the same question if 'object' was a reference.
They are three separate errors:
object = vectorOfObjects.end();
won't work because end() returns a an iterator, and object is a pointer. Those are generally distinct types (A vector can use raw pointers as iterators, but not all implementations do it. Other containers require special iterator types).
object = &vectorOfObjects.end();
doesn't work because you take the address of the returned iterator. That is, you get a pointer to an iterator, rather than a pointer to an Object.
object = &(*vectorOfObjects.end());
doesn't work because the end iterator doesn't point to a valid element. It points one past the end of the sequence. And so, it can't be dereferenced. You can dereference the last element in the sequence (which would be --vectorOfObjects.end()), but not an iterator pointing past the end.
Finally, the underlying problem/confusion might be that you think an iterator can be converted to a pointer. In general, it can't. If your container is a vector, you're guaranteed that elements are allocated contiguously, like in an array, and so a pointer will work. But for, say, a list, a pointer to an element is useless. It doesn't give you any way to reach the next element.
Because .end() returns an iterator, not an Object, which isn't even a valid member of the vector.
Even using begin(), which returns a valid object, you'd need the following:
The correct way would be:
std::vector<Object> vec;
std::vector<Object>::iterator it;
//....
it = vec.begin();
Object o = *it;
This is because by convention end does not point to a valid location in the container: it sits at a location one past the end of the container, so dereferencing it is illegal.
The situation with begin() is different: you can dereference it when v.begin() != v.end() (i.e. when the container is not empty):
object = *vectorOfObjects.begin();
If you need to access the last element, you can do this:
vector<object>::const_iterator i = vectorOfObjects.end();
i--;
cout << *i << endl; // Prints the last element of the container
Again, this works only when your vector contains at least one element.
Object* means a pointer to an Object, where a pointer is a memory address. But the .end() method returns an Iterator, which is an object itself, not a memory address.

How Iterator pointers in the STL work

Hey i'm a little confused on how iterators work. Specifically a const_iterator for a class in this case. I understand that they are really just pointers to specific elements of a string or whatever you're working with, but in that case:
I would think of them as being a memory address, making it so you could not just add integers to get to the next item in the string.
Here's the code I'm confused about:
string::const_iterator iCharacterLocater;
for ( iCharacterLocater = strSTLString.Begin();
iCharacterLocater != strSTLString.end();
++ iCharacterLocater )
{
cout << "Character [ " << nCharOffset ++ <<"] is: ";
cout << *iCharacterLocater << endl;
}
Thanks!! =)
It's a bit more complicated than that. Iterators refer to the GOF design pattern of the same name, and, in C++, are applied in such a way that they look just like pointers. C++ lets you overload operators, which means that custom types can behave in specific ways when certain operators are used on them.
There are several types of iterators in C++, with varying feature levels. The underlying representation of a vector and of a string are both simple enough that iterators behave pretty much exactly like pointers: you can add numbers to them to seek a specific item. For instance, myVector.begin() + 5 returns an iterator to the 6th element of the vector (6th because indices are zero-based, and 0 would be the first). String iterators also let you do this.
String constant iterators behave much like constant char pointers. When you see const char* foo, it doesn't mean you can't change foo–it just means you can't change what it points to. So when you see std::string::const_iterator foo, it doesn't mean you can't change foo. It just means you can't change what it references.
const char* foo = "abcd";
foo = "zyxwvu"; // valid: the pointer itself can be changed
*foo = 't'; // invalid: the pointed data can't be changed
*(foo + 2) == 'x'; // true
std::string myString = "zyxwvu";
std::string::const_iterator foo = myString.begin();
foo = myString.begin() + 2; // valid: the iterator itself can be changed
*foo = 't'; // invalid: the pointed data can't be changed
*(foo + 2) == 'x'; // true
If you don't attempt to modify data, iterators and const iterators behave just the same. Also, except that there is no direct conversion between the two, a pointer to the contents of a string and an iterator to the contents of a string behave exactly the same.
They are a memory address. The thing about these STL containers is that when you store 10 elements in one, those elements are all adjacent just for this reason. So that when you itr++, it points to the next memory address, which is guaranteed to be the next element.
So an std::string just sits on top of a character array. Those characters are all side by side in memory. If you're pointing to one character, and you increment the pointer, you are now pointing to the next pointer. std::string::begin() returns a pointer to the first character, and std::string::end() returns a pointer to the position after the last character.
const std::string::iterator means that you can't modify the iterator. So you can't increment it, or make it point to something else.
std::string::const_iterator means you can't modify the value that the iterator points to. So you can change which value the iterator is pointing to (itr++), but you can't change the actual value at that memory address.
Iterator is basically a pointer, correct ! But what really important is to what it pointing.
What I think is, iterator is the pointer to the structure defined as type.
For example,
for vector of type string, iterator will be a pointer to the string
structure (String is the system defined structure)
For vector of type classA, iterator will be a pointer to the classA
structure (basically class is a user defined structure)
The beauty of defining iterator in this way is, we can defined everything in structure form, so we can retrieve everything by defining iterator to it.