Just started programming in C++.
I've created a Point class, a std::list and an iterator like so:
class Point {
public:
int x, y;
Point(int x1, int y1)
{
x = x1;
y = y1;
}
};
std::list <Point> pointList;
std::list <Point>::iterator iter;
I then push new points onto pointList.
Now, I'm needing to iterate through all the points in pointList, so I need to loop using the iterator. This is where I get screwed up.
for(iter = pointList.begin(); iter != pointList.end(); iter++)
{
Point currentPoint = *iter;
glVertex2i(currentPoint.x, currentPoint.y);
}
Update
You guys were right, the problem isn't in my iterating the list. It appears the problem is when I am attempting to push something on to the list.
Exact error:
mouse.cpp: In function
void mouseHandler(int, int, int, int)': mouse.cpp:59: error: conversion fromPoint*' to non-scalar type `Point' requested
Those lines are:
if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN)
{
Point currentPoint = new Point(x, y);
pointList.push_front(currentPoint);
}
What does it conversion between Point* to non-scalar type Point? I'm just trying to create new points and push them onto the list here.
That should be a valid bit of code.
#include <iostream>
#include <list>
class Point {
public:
int x, y;
Point(int x1, int y1)
{
x = x1;
y = y1;
}
};
int main()
{
std::list<Point> points;
points.push_back(Point(0, 0));
points.push_back(Point(1, 1));
points.push_back(Point(2, 2));
std::list<Point>::iterator iter;
for(iter = points.begin(); iter != points.end(); ++iter)
{
Point test = *iter;
std::cout << test.x << ", " << test.y << "; ";
}
std::cout << std::endl;
return 0;
}
Using this code:
jasons-macbook41:~ g++ test.cpp
jasons-macbook41:~ ./a.out
0, 0; 1, 1; 2, 2;
jasons-macbook41:~
Although I wouldn't create a temporary copy of the Point as your code does. I'd rewrite the loop like this:
for(iter = points.begin(); iter != points.end(); ++iter)
{
std::cout << iter->x << ", " << iter->y << "; ";
}
An iterator is syntactically similar to a pointer.
EDIT: Given your new problem, drop the "new" from the construction line. That's creating a pointer to a Point, as opposed to a Point on the stack. This would be valid:
Point* temp = new Point(0, 0);
Or this:
Point temp = Point(0, 0);
And you'd be better off with the latter.
a few things..
- Did you try
iter->xanditer->yinstead of copying the value? - the error you mention is hard to understand. You are not trying to get x and y via the iterator, you are copying the iterator data to a new point.
EDIT:
according to new information in the OP. You are trying to new into a non-pointer object and then trying to stuff the point into a vector that only accepts objects. You either have to make the vector a vector of pointers and remember to delete them afterwords or create the new point on the stack and copy them into the vector with a standard assign. Try this:
if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN)
{
Point currentPoint = Point(x, y);
pointList.push_front(currentPoint);
}
If already have a function you want to apply to a whole list the std::for_each is the way to go, e.g.,
std::for_each(pointList.begin(), pointList.end(), myGreatFunction);
If you have to write the for loop then something like this:
std::list<Point>::iterator itEnd = pointList.end();
for(std::list<Point>::iterator itCur=pointList.begin(); itCur != itEnd; ++itCur) {
yourFunction(itCur->x, itCur->y);
}
Notes:
- ++itCur can be more efficient than itCur++ due to the return types (reference vs value/copy)
The non-scalar issue is because you're assigning a Point pointer (return value of operator new) to a Point stack object (as it's not Point* in your code).
I would recommend saying
Point currentPoint(x, y);
pointList.push_front(currentPoint);
Note that currentPoint will be copied into your list; the implicitly-generated copy constructor of Point (because you didn't declare a Point(const Point& other) constructor in your class, the compiler did one for you) will copy currentPoint.x and currentPoint.y into the list; in this case, that's fine. Point is small, so the copy expense is low, and it only contains two ints, so a straight up copying of ints is ok.
This answer refers to the edited version of the question.
As gbrandt said in the edited version of his answer, your problem is that you are trying to dynamically allocate an instance of Point and then assign it to a Point object rather than a pointer to Point. The result of new is a pointer to Point, not a Point object -- what you actually want in this case is the latter, which you create without new:
Point currentPoint(x, y);
pointList.push_front(currentPoint);
Because list<T>::push_front() pushes a copy of the Point object on the list, you don't need to do any dynamic allocation here. It's much safer to avoid dynamic allocation when possible as it can easily lead to memory leaks -- e.g. the following alternative code, which compiles and works, results in a memory leak as the object pointed to by currentPoint is never deleted:
Point *currentPoint = new Point(x, y);
pointList.push_front(*currentPoint); // Notice the "*"
Of course you could just add delete currentPoint; to the end to remove the leak, but why use slow dynamic allocation when stack-based allocation does the job faster and more simply?
Here's how I typically approach such loops, if you don't want to use std::foreach:
for (iter curr = pointListObject.begin(), end = pointListObject.end(); curr != end; ++curr)
{
glVertex2i(curr->x, curr->y);
}
Be careful of these points:
- pointListObject is an instance of pointList; if you use the class (the type pointList, and not an instance of pointList) you're in troble, but the compiler will whine a lot. Same with iter. It just makes things easier to grok if you keep typenames and instancenames separate.
- Doing a joint initialization of the iterators like this lets you keep the initialization of end inside the loop (good for scoping) while keeping the per-loop execution cheap.
Did you cut and paste this code into SO from your .cpp file, or did you retype it? From the sound of your error message, I would guess that the original code says
glVertex2i(iter.x, iter.y);
Which, as gbrandt pointed out, doesn't properly dereference the iterator.
I would rewrite the loop as follows:
std::list<Point>::const_iterator iter = pointList.begin();
const std::list<Point>::const_iterator end = pointList.end();
for (; iter != end; ++iter) {
const Point& p = *iter;
glVertex2i(p.x, p.y);
}
The main changes are to use const_iterators instead of non-const, as your loop doesn't intend to modify the list contents. Then, grab the values of begin() & end() exactly once, use preincrement, and dereference the iterator once into a const reference. This way you have no copying, where your original code copied the Point object that *iter referred to, and you avoid dereferencing the iterator twice for about as much efficiency as you can get here.
Now, for some unsolicited OpenGL advice, I'd also point out that vertex arrays are probably a better choice than immediate mode (glVertex*) calls.
Hope this helps...
来源:https://stackoverflow.com/questions/535223/why-cant-i-push-this-object-onto-my-stdlist