Iterating through a vector via pointers - c++

I'm currently writing some code that iterates through a vector and calls a simple print method for every element within that vector; however, I have very limited experience with vectors and I'm having some issues getting the compiler to accept this one particular segment of code:
std::vector<Buyer *>:: iterator it;
Buyer *b;
for(it = buyers->begin(); it != buyers->end(); ++it) {
b = *it;
cout << b->getName();
}
where buyers is a vector containing Buyer pointers. I'd much rather use an array for this purpose, but as I'm required to use a vector for this particular point, I'm unsure of how to iterate through it and ended up trying an iterator to get through.
The error message that springs up is:
Retailer.cpp:37:17: error: base operand of ‘->’ is not a pointer
for(it = buyers->begin(); it != buyers->end(); ++it) {
^
Retailer.cpp:37:40: error: base operand of ‘->’ is not a pointer
for(it = buyers->begin(); it != buyers->end(); ++it) {
From what I understand, there's apparently a pointer somewhere in that mess I'm not dereferencing, but I'm not sure which element that is or where I should dereference it... any ideas for a programmer who's had little experience with c++ vectors/iterators?

Your error is that byuers is not a pointer, but you write buyers->begin(). This should have been a buyers.begin() instead. (The same for buyers->end() of course).
You can simplify your code significantly, if you use modern c++11:
for(Buyer* b : buyers)
{
// do something
}

The other answers have already explained what your error is but they have not given you an answer in C++ 03, which you may be using (since I'm not sure, I'll add my own answer).
In the old C++, C++ 03, you would need to change:
for(it = buyers->begin(); it != buyers->end(); ++it) {
to
for(it = buyers.begin(); it != buyers.end(); ++it) {
As was already stated in the other answers, this is because the -> requires a pointer to the left of it but you don't have a pointer, you have an object so you need to use the . operator.

Related

Trouble using iterator on a list of objects

So I have a class called symbol, which is made up of 4 strings which are all public. I created a list of these and I want to do a look ahead on this list. This is what I have so far. I looked up the iterator methods and it says it supports the + operator but I get an error for this.
bool parser::parse(list<symbol> myList){
//Will read tokens by type to make sure that they pass the parse
std::list<symbol>::const_iterator lookAhead = myList.begin();
if ((lookAhead + 1) != myList.end)
lookAhead++;
for (std::list<symbol>::const_iterator it = myList.begin(); it != myList.end(); ++it){
if (it->type == "") {
}
}
return true;
}
I get an error when trying to add 1 to lookAhead. What are some good ways of creating a look ahead for a list?
Thanks,
Binx
A linked list does not support random access iterators, i.e. you cannot add an integer to its iterators.
Use std::next(lookAhead) to get the next iterator instead, or std::advance(lookAhead, 1). These functions know what kind of iterator is being passed, and will use a random seek if possible (e.g. with std::vector's random-access iterators), or manually advance (with a loop in the case of std::advance()) otherwise, as in this case.
Be careful advancing on iterators unconditionally, though -- advancing past end() is undefined!
You can read more about the different categories of C++ iterators here.
Side note: You're copying the entire list when it's passed in, since you're passing it by value. You probably want to pass it by reference instead (list<symbol> const& myList). You can also simplify your code using the C++11 auto keyword, which deduces the type automatically from the type of the expression that initializes the variable:
bool parser::parse(list<symbol> const& myList){
// Will read tokens by type to make sure that they pass the parse
auto lookAhead = myList.begin();
if (lookAhead != myList.end() && std::next(lookAhead) != myList.end())
++lookAhead;
for (auto it = myList.begin(); it != myList.end(); ++it){
if (it->type == "") {
}
}
return true;
}

Using iterator over set of pointers to call it's pointer object methods

I am a beginner as comes to working with iterators and want to iterate through names of my points printing them out. I do not know how to access them, help me out please with an idea. My approach looks like this:
set<Point::Ptr> points = world->getPoints(); // have set of pointers to Point
Point::CPtr myPoint = *points.begin(); // dereferenced iterator to the first element
Point::CPtr lastPoint = *points.rbegin(); //dereferenced iterator to the last valid element
for(set<Point::Ptr>::iterator it = *points.begin(); it != points.end(); it++) {
ROS_INFO("points are: %s: ", myPoint.get()->getName().c_str());
}
Normally for iterator in a loop it shall be set to the first element of the set. But since set contains pointers and I want to be able to call functions available for objects inside those pointers, I tried this way.
It works for a one only element like that, giving me desired name:
ROS_INFO("myPoint pointer gives %s: ", myPoint.get()->getName().c_str());
EDIT:
typedef boost::shared_ptr CPtr;
it in the loop below is an iterator. Hence, to access the element that it refers to, you need to dereference it (*it)or use the member access operator (it->).
set<Point::Ptr> points = world->getPoints(); // have set of pointers to Point
for(set<Point::Ptr>::iterator it = points.begin(); it != points.end(); it++) {
ROS_INFO("points are: %s: ", it->get()->getName().c_str());
ROS_INFO("points are: %s: ", (*it).get()->getName().c_str());
}
There also is a typo or a deliberate syntax error here:
for(set<Point::Ptr>::iterator it = *points.begin(); it != points.end(); it++) {
// ^^^
You want the iterator itself to iterate over the loop, not the value it refers to.
Edit: for OP's and future reference moved here from a comment:
I don't have a reference to Point::Ptr, but it appears to be a pointer class. Thus, to get the Point object that an object of this pointer class stores, you need to call get(). This function returns you a Point* pointer (which is also called a raw pointer) that you can then use like you always use pointers to class objects. In short, this is an example of the common concept of wrapping raw pointers into (more or less) smart pointer classes.
See:
for(set<Point::Ptr>::iterator it = points.begin(); it != points.end(); it++) {
const Point::Ptr pointer= *it;
ROS_INFO("points are: %s: ", pointer.get()->getName().c_str());
}
One more edit:
Normally for iterator in a loop it shall be set to the first element of the set.
Wrong. The iterator is set to the iterator pointing to the first element of the set. As #RSahu also pointed out below, you can't assign a container element to an iterator, this is (a) a logical error and (b) a syntax error. And, you may want to begin the iteration from a position other than the collection start, so the "to the first element" part is not quite correct either.
And one more for OP's reference:
What is a smart pointer and when should I use one?
Is it a good practice to always use smart pointers?
When should I use raw pointers over smart pointers?
Using
for(set<Point::Ptr>::iterator it = *points.begin(); it != points.end(); it++)
is a problem since it is an iterator, but *points.begin() is not. You need to use:
for(set<Point::Ptr>::iterator it = points.begin(); it != points.end(); it++)
{
Point::CPtr myPoint = *it;
// Now you can use myPoint
}
If you are able to use a C++11 compiler, you simplify that with a range-for loop.
for( auto myPoint : points)
{
// Now you can use myPoint
}

Foreach through a vector containing pointers in c++

I made a map filled with vectors which looks like this:
std::map<int, std::vector<CClass*>> pointers = getMap();
And now I want to go through every slot of the map and also through every slot of the vector stored in the map.
This is how it goes through the map:
for (std::map<int, std::vector<CClass*>>::iterator it = pointers.begin(); it != pointers.end(); it++)
This works fine and it goes through every object just like I want it to.
But now I want to go through every slot in the vector and I tried it like this:
for (std::vector<CClass*>::iterator playerIt = it->second.begin(); playerIt != it->second.end(); playerIt++)
If I want to access the value stored in it the compiler gives me this error:
file.cpp(552) : error C2839: Ungültiger Rückgabetyp 'CClass **' für überladenen Operator '->'
Which means "invalid return-type 'CClass **' for overweight operator '->'
regards
You can use range-based for loops in C++11 to handle this more readably
for (auto& element : pointers)
{
for (auto& player : element.second)
{
// player will be a CClass* that you can use
std::string name = player->GetName(); // For example
}
}
playerIt is an iterator, not a pointer to a CClass. You need to dereference the iterator to get a pointer to CClass:
CClass * player = (*playerIt);
player->ClassMethod(...); // or whatever
playerIt is an iterator that returns a CClass*, but you dereference the iterator via operator->, so you need to dereference the pointer that is returned by the iterator.
So you are possibly saying playerIt->cclass_method() when you should be saying (*playerIt)->cclass_method();
Of course, storing shared_ptr<>, or unique_ptr objects in your vector might be better and easier to understand, along with using typedef to alias the vector<> part of the map.

C++ - Accessing member functions from a map of object pointers, in a seperate class via getter functions

I'm fairly new to C++, I've tried to figure this out on my own but can't quite get there.
I've defined a map of pointers to a group of dynamically allocated objects in one class, with strings as the keys, along with two iterators (begin() and end()), and two getter functions corresponding to each iterator.
class a{
std::map<string, Fruit*> fruitSalad;
std::map<string, Fruit*>::iterator begin = fruitSalad.begin(), end = fruitSalad.end();
std::map<string, Fruit*>::iterator getBeginIter() const;
std::map<string, Fruit*>::iterator getEndIter() const;
};
the objects referenced in the map, and their member functions need to be accessible in a separate driver class. To test my implementation I've been trying to print values from the objects with a for loop, by accessing the iterators via their accessors, as shown in the code below.
#include "a.h"
int main(){
A fruitBowl;
std::map<string, Object*>::iterator iter;
for(iter = fruitBowl.getBeginIter(); iter != fruitBowl.getEndIter(); iter++){
cout << iter.getName() << " " << iter.getQuantity() << endl;
}
}
But I am getting the following error
error: 'std::map<std::basic_string<char>, Fruit*>:: iterator' has no member named getName()
error: 'std::map<std::basic_string<char>, Fruit*>:: iterator' has no member named getQuantity()
I assume I'm doing something wrong with the assignment of the iterators in my driver class, but what exactly am I doing wrong?
First, when you write iter = fruitBowl.getBeginIter();, iter is an iterator. This is a pointer-like object. If you want to access the method of the pointed-to object, you must first dereference it.
Second, the objects contained in the std::map<foo, bar> are std::pairs of foo, bar.
So the usage looks like
for(iter = fruitBowl.getBeginIter(); iter != fruitBowl.getEndIter(); iter++){
auto pFruit = (*iter).second;
cout << (*pFruit).getName() << " "
<< (*pFruit).getQuantity() << endl;
}
The first dereference is to access the value of the key-value pair in the map;
the second one is to access the Fruit referenced by the pointer.
Or, using the syntactic sugar for pointer manipulation:
for(iter = fruitBowl.getBeginIter(); iter != fruitBowl.getEndIter(); iter++){
auto pFruit = iter->second;
cout << pFruit->getName() << " "
<< pFruit->getQuantity() << endl;
}
Thanks for the responses guys, I appreciate your help.
Turns out it was a relatively simple problem and fix as most beginner programming errors are. I misinterpreted Joachim Pileborg's comment earlier in the thread- I was in fact using begin() and end() to start with, although this comment did set me on the right line of thinking.
The problem was that although I initialized the the iterators that I named 'begin' and 'end' with the iterators returned from the iterator funcitons begin() and end(), I was doing so immediately after I defined the map, before it had any values in it- as shown below.
std::map<string, Fruit*> fruitSalad;
std::map<string, Fruit*>::iterator begin = fruitSalad.begin(), end = fruitSalad.end();
So i guess this meant my iterators both pointed to the same memory location, so when I accessed these iterators via the getters in the driver class, the for loop would terminate just as soon as it would begin which is why no values were being printed even after fixing the original errors in my code as pointed out by mookid.
To remedy this I simply initialised the values of the pointers in class a inside the constructor, which is where the values of the map are read in from a file as shown below.
// class a constructor
a(){
... // initialise some other variables
loadFruitValues(); // reads values in from a .txt file to the map
iter1 = fruitSalad.begin();
iter2 = fruitSalad.end();
}
Now when the code runs the iterators returned correctly point to the beginning and end of the map, allowing the for loop to iterate over the contents stored inside the map.
Thanks again for the replies, I'd still be stuck without all of your input. Both answers helped me equally but I think I can only site one as being the one that helped me the most. And my apologies for my original question not being formatted correctly, it's my first post- I'll try to make sure my next ones on point.

Accessing vector elements inside another vector through an iterator?

std::vector< std::vector<coords> >::iterator iter;
for(iter = characters.begin(); iter != characters.end(); iter++)
{
std::vector<coords>* cha = iter; // doesn't work.
}
// does work.
std::vector<coords>* character = &characters.at(0);
coords* first = &character->at(0);
And I don't get why. Isn't iter supposed to be a pointer to an element of the type that it's container is supposed to 'contain'?
Anyone willing to shed light on this?
By doesn't work I mean:
error C2440: 'initializing' : cannot convert from 'std::_Vector_iterator<_Ty,_Alloc>' to 'std::vector<_Ty> *'
Which doesn't make a whole lot of sense to me.
An iterator is a type that can be dereferenced like a pointer, i.e., it has an explicit operator*() and operator->(). It doesn't have to be a pointer.
So use &*iter if you want to get the address of the vector.
To clarify further on MSN's answer, you can think of the iterator as a wrapper to an individual item of the container, but it also has some smarts for incrementing (++iter), decrementing (++iter) etc. Remember, the underlying data structure may not be a contiguous block of memory depending on the container type / implementation. To access the actual value, you can
1) derefence the iterator, eg
Type t = *iter;
2) treat the iterator as a pointer to the container type, eg
iter->someFuncOnTheContainerType();
I know it's obvious now (in hindsight), but in your for loop you could also try:
std::vector<coords> & cha = * iter;
Also, not what you are asking for, and just FYI, but vectors support random access iterators. Meaning you could also write:
for( size_t i=0; i<characters.size(); i ++ )
And, if you needed to convert back to an iterator, you could use:
characters.begin() + i
It's not the C++ way of doing things, it breaks the generic iterator philosophy, but it has its uses.