Почему я не могу поместить этот объект в мой список std :: list? - PullRequest
4 голосов
/ 11 февраля 2009

Только что начал программировать на 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 from Point * 'запрошен нескалярный тип `Point'

Эти строки:

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

}

Что означает преобразование между Point * в нескалярный тип Point? Я просто пытаюсь создать новые точки и вставить их в список здесь.

Ответы [ 7 ]

2 голосов
/ 11 февраля 2009

Это должен быть правильный бит кода.

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

Итератор синтаксически похож на указатель.

EDIT: Учитывая вашу новую проблему, отбросьте «новое» со строительной линии. Это создает указатель на точку, а не на точку в стеке. Это будет действительно:

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

Или это:

Point temp = Point(0, 0);

И с последним вам будет лучше.

2 голосов
/ 11 февраля 2009

несколько вещей ..

  • Вы пробовали iter->x и iter->y вместо копирования значения?
  • ошибку, которую вы упоминаете, трудно понять. Вы не пытаетесь получить x и y через итератор, вы копируете данные итератора в новую точку.

EDIT:

согласно новой информации в ОП. Вы пытаетесь перейти в объект без указателя, а затем пытаетесь вставить точку в вектор, который принимает только объекты. Вы должны либо сделать вектор вектором указателей и не забудьте удалить их после слов, либо создать новую точку в стеке и скопировать их в вектор со стандартным присваиванием. Попробуйте это:

if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN)
{
    Point currentPoint = Point(x, y);
    pointList.push_front(currentPoint);
}
1 голос
/ 11 февраля 2009

Этот ответ относится к отредактированной версии вопроса.

Как сказал гбрандт в отредактированной версии своего ответа, ваша проблема в том, что вы пытаетесь динамически выделить экземпляр Point и затем назначить его Point объекту , а не указатель на Point. Результатом new является указатель на Point, а не Point объект - в данном случае вам действительно нужен последний, который вы создаете без new:

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

Поскольку list<T>::push_front() помещает копию объекта Point в список, вам не нужно выполнять динамическое выделение здесь. Гораздо безопаснее избегать динамического выделения, когда это возможно, поскольку это может легко привести к утечкам памяти - например, следующий альтернативный код, который компилируется и работает, приводит к утечке памяти, так как объект, на который указывает currentPoint, никогда не delete d:

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

Конечно, вы могли бы просто добавить delete currentPoint; в конец, чтобы устранить утечку, но зачем использовать медленное динамическое распределение, когда распределение на основе стека делает работу быстрее и проще?

1 голос
/ 11 февраля 2009

Нескалярная проблема заключается в том, что вы присваиваете указатель Point (возвращаемое значение оператора new) для объекта стека Point (поскольку это не Point * в вашем коде).

Я бы порекомендовал сказать

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

Обратите внимание, что currentPoint будет скопирован в ваш список; неявно сгенерированный конструктор копирования Point (поскольку вы не объявили конструктор Point (const Point и др.) в своем классе, компилятор сделал это за вас) скопирует currentPoint.x и currentPoint.y в список; в этом случае это нормально. Точка мала, поэтому затраты на копирование невелики и содержат только два целых числа, так что копирование целых чисел в порядке.

1 голос
/ 11 февраля 2009

Если у вас уже есть функция, которую вы хотите применить ко всему списку, 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 ++, благодаря возвращаемым типам (ссылка на значение / копия)
0 голосов
/ 11 февраля 2009

Вы вырезали и вставили этот код в SO из вашего файла .cpp или перепечатали? Судя по звуку вашего сообщения об ошибке, я предполагаю, что в исходном коде написано

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 () ровно один раз, используйте предварительный инкремент и разыменуйте итератор один раз в константную ссылку. Таким образом, у вас не будет копирования, где ваш исходный код скопировал объект Point, на который * iter ссылался, и вы избегаете разыменования итератора дважды, чтобы получить как можно большую эффективность.

Теперь, для некоторых незапрошенных советов OpenGL, я бы также отметил, что массивы вершин, вероятно, являются лучшим выбором, чем вызовы непосредственного режима (glVertex *).

Надеюсь, это поможет ...

0 голосов
/ 11 февраля 2009

Вот как я обычно подхожу к таким циклам, , если вы не хотите использовать std :: foreach :

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

Будьте осторожны с этими пунктами:

  • pointListObject является экземпляром pointList; если вы используете класс (тип pointList, а не instance of pointList), то вы в тробле, но компилятор будет скулить много. То же самое с Итером. Это просто облегчает задачу, если вы держите имена и имена экземпляров отдельно.
  • Выполнение совместной инициализации итераторов, подобной этой, позволяет сохранить инициализацию end внутри цикла (хорошо для определения объема), сохраняя при этом дешевое выполнение для каждого цикла.
...