Foreach through a vector containing pointers in c++ - 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.

Related

std::map find() returning error

I am trying to compile the below code in VS2015. The first version of my std::map is compiling, but the seconds version does not compile. Please let me know what I am doing wrong here..
std::map<int, std::string> _p;
typedef std::pair<int, std::string> _q;
_p.insert(_q(0, "Football0"));
_p.insert(_q(1, "Football1"));
std::string str = _p[1]; //OK...compiles and executes, no error, str = "Football1" as expected
std::map<int, DataDictionary> _p1;
typedef std::pair<int, DataDictionary> _q1;
DataDictionary dd1;
dd1.i = 0;
dd1.version = "ver1";
_p1.insert(_q1(0, dd1));
DataDictionary dd2;
dd2.i = 0;
dd2.version = "ver2";
_p1.insert(_q1(1, dd2));
DataDictionary DD = _p1.find[1]; //error C3867: 'std::_Tree<std::_Tmap_traits<_Kty,_Ty,_Pr,_Alloc,false>>::find': non-standard syntax; use '&' to create a pointer to member
Even if I decide to change my std::map and use the following, I am getting the same error :
std::map<std::string, DataDictionary> _p1;
DataDictionary DD = _p1.find["1"]; //ERROR
I am trying to use map with the DataDictionary structure, and use _p1.find["1"] syntax to access the elements, as I am assuming that this approach will be faster than declaring iterator to the map, and then use find(). Please help. Thanks,
I am trying to use map with the DataDictionary structure, and use _p1.find["1"] syntax to access the elements
No, you are trying to use subscript operator on a member function:
find("1") would work.
find["1"] should not compile.
Consider using either _p1.find("1"), or _p1["1"]. The difference between them is that find returns a pair with a position in the map and a boolean flag an iterator (which may be past the end of the mapped sequence), and the subscript operator (["1"]) returns either a reference to the existing element, or it adds an element (if one is not found) and returns a reference to that.
To check if the map contains the key, use if(_p1.count("1")) instead.
I think you meant
_p1.find("1");
it returns an iterator to the found item.
use
std::map<std::string, DataDictionary>::iterator item = _p1.find("1");
or
in C++11 you can do
auto item = _p1.find("1");

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
}

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.

BOOST_FOREACH over a vector of pointers

I want to use the BOOST_FOREACH macro to iterate over a bunch of values in a vector of mine. The vector looks like this:
struct _Element
{
int key;
// more variables here
}
elements = new std::vector<_Element *>;
I'm very new to C++, and I'm a bit stumped as to how I would actually iterate over the contained _Element *'s. Why doesn't this work?
BOOST_FOREACH(_Element *currentElem, rootElement->_document->elements)
{
// do stuff
}
Compiling this gives me an error:
shared.cc:146:37: error: no viable conversion from 'std::__1::vector<_Element *, std::__1::allocator<_Element *> >' to '_Element *'
BOOST_FOREACH(_Element *currentElem, rootElement->_document->elements)
~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The type of elements is vector<_Element *>*, so you need to dereference it before passing it to BOOST_FOREACH.
BOOST_FOREACH(_Element *currentElem, *(rootElement->_document->elements))
{
// do stuff
}
That will fix the compilation error, but since you're new to C++, there's a very good chance you don't need all those pointers you've declared. For instance, your code should probably look like this:
struct Element // do not use leading underscore followed by
// uppercase letter, that's reserved
{
int key;
// more variables here
};
std::vector<Element> elements = std::vector<Element>;
// vector of Element, not Element*. And elements is a vector, not vector *
Finally, if you have a compiler that supports C++11's range based for you don't need BOOST_FOREACH.
for(auto&& currentElem : rootElement.document.elements)
// notice that I've gotten rid of all the pointers within rootElement
{
// currentElem is a reference to the current element in the elements vector
}
The statement
elements = new std::vector<_Element *>;
indicates that elements is of pointer type.
Technically that means that you need to dereference it, *elements, for use with BOOST_FOREACH.
But that's still wholly wrong on the level of good programming practice.
Instead:
Let elements just be a vector, directly. Not a pointer.
Don't use new.
Use a C++11 range-based for if your compiler supports it. If not, then upgrade your compiler and use a C++11 range-based for.
It can look like this:
for( auto const& item : elements )
{
// Do whatever
}
or if the items are of small/simple enough type that a bit of value copying doesn't matter, just
for( auto const item : elements )
{
// Do whatever
}
In passing: in addition to avoiding needless huge library dependencies, and avoiding use of raw pointers where practical, you might want to reconsider using a prefix underscore as a member name convention. Prefix underscores are used by a lot of other software and are reserved in the global namespace. A nice alternative is a suffix underscore.
BOOST_FOREACH expects a container not a pointer to a container as the second argument.
Use
BOOST_FOREACH(_Element *currentElem, *(rootElement->_document->elements))
{
// do stuff
}
Do :
BOOST_FOREACH(_Element *currentElem, *(rootElement->_document->elements))
{
.....
}
Or if your compiler supports C++11, prefer using the built-in range iteration:
for(auto element : *(rootElement->_document->elements))
{
....
}

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.