4

刚开始用 C++ 编程。

我创建了一个 Point 类、一个 std::list 和一个迭代器,如下所示:

class Point { 
public:
    int x, y;
    Point(int x1, int y1)
    {
        x = x1;
        y = y1;
    }
};

std::list <Point> pointList;
std::list <Point>::iterator iter;

然后我将新点推送到 pointList 上。

现在,我需要遍历 pointList 中的所有点,所以我需要使用迭代器进行循环。这就是我搞砸的地方。

for(iter = pointList.begin(); iter != pointList.end(); iter++)
{
    Point currentPoint = *iter;
    glVertex2i(currentPoint.x, currentPoint.y);
}


更新

你们是对的,问题不在于我迭代列表。看来问题出在我试图将某些内容推送到列表时。

确切的错误:

mouse.cpp:在函数void mouseHandler(int, int, int, int)': mouse.cpp:59: error: conversion fromPoint*' 中请求非标量类型“Point”

这些行是:

 if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN)
{
    Point currentPoint = new Point(x, y);
    pointList.push_front(currentPoint);

}

Point* 到非标量类型 Point 之间的转换是什么?我只是想创建新点并将它们推到这里的列表中。

4

7 回答 7

2

一些东西..

  • 您是否尝试过iter->xiter->y不是复制该值?
  • 你提到的错误很难理解。您不是试图通过迭代器获取 x 和 y,而是将迭代器数据复制到新点。

编辑:

根据 OP 中的新信息。您正在尝试新建一个非指针对象,然后尝试将该点填充到仅接受对象的向量中。您要么必须使向量成为指针向量并记住在后面删除它们,要么在堆栈上创建新点并使用标准分配将它们复制到向量中。试试这个:

if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN)
{
    Point currentPoint = Point(x, y);
    pointList.push_front(currentPoint);
}
于 2009-02-11T02:50:48.767 回答
2

那应该是一段有效的代码。

#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;
}

使用此代码:

jasons-macbook41:~ g++ test.cpp
jasons-macbook41:~ ./a.out
0, 0; 1, 1; 2, 2; 
jasons-macbook41:~ 

尽管我不会像您的代码那样创建 Point 的临时副本。我会像这样重写循环:

for(iter = points.begin(); iter != points.end(); ++iter)
{
    std::cout << iter->x << ", " << iter->y << "; ";
}

迭代器在语法上类似于指针。

编辑:鉴于您的新问题,请从施工线上删除“新”。那是创建一个指向 Point 的指针,而不是堆栈上的 Point。这将是有效的:

Point* temp = new Point(0, 0);

或这个:

Point temp = Point(0, 0);

而你最好选择后者。

于 2009-02-11T03:03:19.440 回答
1

如果已经有一个要应用于整个列表的函数,则 std::for_each 是要走的路,例如,

std::for_each(pointList.begin(), pointList.end(), myGreatFunction);

如果您必须编写 for 循环,则如下所示:

std::list<Point>::iterator itEnd = pointList.end();
for(std::list<Point>::iterator itCur=pointList.begin(); itCur != itEnd; ++itCur) {
    yourFunction(itCur->x, itCur->y);
}

笔记:

  • 由于返回类型(引用与值/副本),++itCur 可能比 itCur++ 更有效
于 2009-02-11T03:00:39.040 回答
1

非标量问题是因为您将 Point 指针(运算符 new 的返回值)分配给 Point 堆栈对象(因为它不是代码中的 Point*)。

我建议说

    Point currentPoint(x, y);
    pointList.push_front(currentPoint);

请注意,currentPoint 将被复制到您的列表中;Point 的隐式生成的复制构造函数(因为您没有在类中声明 Point(const Point& other) 构造函数,编译器为您做了一个)会将 currentPoint.x 和 currentPoint.y 复制到列表中;在这种情况下,这很好。点小,所以复制成本低,而且它只包含两个整数,所以直接复制整数是可以的。

于 2009-02-11T03:07:14.687 回答
1

这个答案是指问题的编辑版本。

正如 gbrandt 在其答案的编辑版本中所说,您的问题是您正在尝试动态分配 的实例,Point然后将其分配给Point 对象而不是指向 Point. 的结果new是指向 的指针 Point,而不是Point对象——在这种情况下,您真正​​想要的是后者,您可以在没有 的情况下创建它new

Point currentPoint(x, y);
pointList.push_front(currentPoint);

因为list<T>::push_front()将对象的副本推送到Point列表中,所以这里不需要做任何动态分配。尽可能避免动态分配会更安全,因为它很容易导致内存泄漏——例如,下面的替代代码编译和工作,导致内存泄漏,因为指向的对象currentPoint从不deleted:

Point *currentPoint = new Point(x, y);
pointList.push_front(*currentPoint);      // Notice the "*"

当然,您可以delete currentPoint;在最后添加以消除泄漏,但是当基于堆栈的分配更快更简单地完成工作时,为什么要使用慢速动态分配呢?

于 2009-02-11T04:46:46.117 回答
0

如果您不想使用 std::foreach,这是我通常处理此类循环的方法:

for (iter curr = pointListObject.begin(), end = pointListObject.end(); curr != end; ++curr)
{
    glVertex2i(curr->x, curr->y);
}

请注意以下几点:

  • pointListObject 是 pointList 的一个实例;如果你使用类(pointList 类型,而不是pointList的实例),你会遇到麻烦,但编译器会抱怨很多。与 iter 相同。如果你将类型名和实例名分开,它只会让事情更容易理解。
  • 像这样对迭代器进行联合初始化可以让您将 end 的初始化保持在循环内(有利于范围界定),同时保持每个循环的执行成本低。
于 2009-02-11T03:02:33.420 回答
0

您是从 .cpp 文件中将此代码剪切并粘贴到 SO 中,还是重新输入?从您的错误消息的声音中,我猜原始代码说

glVertex2i(iter.x, iter.y);

正如 gbrandt 指出的那样,它没有正确取消引用迭代器。

我将重写循环如下:

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);
} 

主要更改是使用 const_iterators 而不是非常量,因为您的循环不打算修改列表内容。然后,只获取一次 begin() 和 end() 的值,使用 preincrement,并将迭代器解引用一次到 const 引用中。这样您就没有复制,您的原始代码复制了 *iter 引用的 Point 对象,并且您避免了两次取消引用迭代器以获得尽可能高的效率。

现在,对于一些未经请求的 OpenGL 建议,我还要指出,顶点数组可能是比立即模式 (glVertex*) 调用更好的选择。

希望这可以帮助...

于 2009-02-11T03:24:25.567 回答