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.
Related
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
}
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.
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.
I have the following vector passed to a function
void WuManber::Initialize( const vector<const char *> &patterns,
bool bCaseSensitive, bool bIncludeSpecialCharacters, bool bIncludeExtendedAscii )
I want to erase any element that is less in length than 2
I tried the following but it didn't compile even
can you tell me what I am missing here.
for(vector<const char *>::iterator iter = patterns.begin();iter != patterns.end();iter++)
{//my for start
size_t lenPattern = strlen((iter).c_str);
if ( 2 > lenPattern )
patterns.erase(iter);
}//my for end
On top of the problems others have pointed out, it's a bad idea to erase items from the vector as you iterate over it. There are techniques to do it right, but it's generally slow and fragile. remove_if is almost always a better option for lots of random erasures from a vector:
#include <algorithm>
bool less_than_two_characters(const char* str) { return strlen(str) < 2; }
void Initialize(vector<const char*>& v) {
v.erase(std::remove_if(v.begin(), v.end(), less_than_two_characters), v.end());
}
In C++0x you can do that more concisely with a lambda function but the above is more likely to work on a slightly older compiler.
This cannot work, because if you erase something from your vector you invalidate your iterator.
It probably does not compile because you use your iterater in a wrong way. You might try iter->c_str or (*iter).c_str. On the other hand, give us the error message ;)
Next thing, you try to modify a const vector. This is why the compiler is complaining.
You could do this with an index, like this:
for (int i = 0; i < patterns.size(); ++i) {
size_t lenPattern = strlen(patterns[i]);
if (2 > lenPattern) {
patterns.erase(patterns.begin() + i);
--i;
}
}
However, this is not very elegant, as I manipulate the counter...
First, as Tim mentioned, the patterns parameter is a const reference, so the compiler won't let you modify it - change that if you want to be able to erase elements in it.
Keep in mind that iter 'points to' a pointer (a char const* to be specific). So you dereference the iterator to get to the string pointer:
size_t lenPattern = strlen(*iter);
if ( 2 > lenPattern )
iter = patterns.erase(iter);
Also, in the last line of the snippet, iter is assigned whatever erase() returns to keep it a valid iterator.
Note that erasing the element pointed to by iter will not free whatever string is pointed to by the pointer in the vector. It's not clear whether or not that might be necessary, since the vector might not 'own' the strings that are pointed to.
I have two sets and I'm trying to do a union (I get the same error when doing an intersection). Here is the error:
error C3892: 'std::_Tree_const_iterator<_Mytree>::operator *' : you cannot assign to a variable that is const
Code snippet(if I comment out the line with the --> then the code compiles and my work around way of doing the union works fine):
set<Line *>::iterator it;
set<Line *> * newSet = new set<Line *>();
leftLines = pLeft->getSet();
rightLines = pRight->getSet();
-->it = set_union(leftLines->begin(),leftLines->end(),rightLines->begin(), rightLines->end(), newSet->begin());
for(it = leftLines->begin(); it != leftLines->end(); it++)
{
newSet->insert(*it);
}
for(it = rightLines->begin(); it != rightLines->end(); it++)
{
newSet->insert(*it);
}
it = newSet->begin();
while(it != newSet->end())
{
result->insert(*it);
it++;
}
I'm sure this is something silly but I'm kind of lost. I think that code snippet should be enough but I can provide whatever else is needed. Thanks.
This is C++, not Java [edit: or .NET]. You almost certainly want to replace (for example):
set<Line *> * newSet = new set<Line *>();
with just:
set<Line *> newSet;
...or, better still, probably just:
set<Line> newSet;
Although it's impossible to say for certain based on the code you've posted, there's a pretty fair chance that your left and right shouldn't be dealing in pointers either -- if they're going to do anything of the sort, a reference probably makes more sense (though, as I said, based on just what you've posted, it's impossible to say for sure).
Once you've done that, you run into a minor problem: a "normal" iterator over a set (or multiset, map or multimap) is really a const_iterator. Once you insert something into an associative container, you're not allowed to change it because that could destroy the collection's invariant (being sorted). If you want to change an existing item, you need to delete if from the contain, make the change, and insert the changed object back into the container. In your case, you're just inserting new items, so you want an insert_iterator.
Since you're not planning on modifying either left or right, you might as well treat them as const as well:
std::set_union(left.cbegin(), left.cend(),
right.cbegin(), right.cend(),
std::inserter(newSet, newSet.end()));
If you decide to simulate set_union on your own, you can do something like this:
std::set<Line> newSet(left.cbegin(), left.cend());
std::copy(right.cbegin(), right.cend(), std::inserter(newSet, newSet.end()));
Edit:
Instead of passing around pointers to containers, you normally want to pass around iterators into the containers. For example, to print out the contents, you apparently now have something like:
void print_data(std::vector<Line *> const *data) {
for (int i=0; i<data->size(); i++)
std::cout << *(*data)[i] << "\n";
}
It probably has more formatting and such, but for the moment we'll ignore those details and assume it's this simple. To write the data directly from a container of your choice, you normally want a template that will accept iterators of an arbitrary type:
template <class inIt>
void print_data(inIt begin, inIt end) {
while (begin != end)
std::cout << *begin++ << '\n';
}
We can, however, go a step further than that, and specify the output as an iterator as well:
template <class inIt, class outIt>
void print_data(inIt begin, inIt end, outIt dest) {
while (begin != end) {
*dest++ = *begin++;
*dest++ = '\n';
}
}
You could go one more step, and allow the user to specify the delimiter to be used between the items, instead of always using '\n', but at that point, you'd just be duplicating something what's already in the standard library -- a combination of std::copy and an std::ostream_iterator, which is how you probably want to deal with this in reality:
std::copy(newSet.begin(), newSet.end(),
std::ostream_iterator<Line>(std::cout, "\n"));
Note, however, that as far as the standard library cares, an ostream_iterator is just another iterator. If you're just going to print out the union of left and right, you can skip even creating a set to hold that union, and just print it out directly:
std::set_union(left.cbegin(), left.cend(),
right.cbegin(), right.cend(),
std::ostream_iterator<Line>(std::cout, "\n"));
The fact that an ostream_iterator writes to a file instead of putting things into a normal collection is entirely irrelevant to the standard library. It has a few classes of iterators, and can write output to any iterator that models the correct class.
Now, I may be jumping the gun, so to speak -- maybe need to do other processing on the data before you write it to the console. My point isn't that you necessarily have to write the union directly to standard output, but just that you don't necessarily have to write it to some other collection before you print it out.
set iterators aren't output iterators. Use this:
set_union(leftLines->begin(),leftLines->end(),rightLines->begin(), rightLines->end(), inserter(*newSet, newSet->begin()));
Also, why're you filling newSet? Leave it as is after the union/intersection or the union/intersection will be pointless.
set<Line *>::iterator it;
set<Line *> newSet; // No need to `new` this
leftLines = pLeft->getSet();
rightLines = pRight->getSet();
set_union(leftLines->begin(),leftLines->end(),rightLines->begin(), rightLines->end(), inserter(newSet, newSet.begin()));
// Assuming you really need the below code - you could likely just make an inserter directly on `result` instead of the copying.
it = newSet.begin();
while(it != newSet.end())
{
result->insert(*it);
it++;
}