Как я случайно перезаписываю ссылки на эти указатели? - PullRequest
6 голосов
/ 13 февраля 2009

Последний вопрос на сегодня, обещаю. Эти указатели вызывают у меня серьезную головную боль.

У меня есть std :: list <Point> с именем Polygon и std :: список полигонов, определенных как:

typedef std::list<Point> Polygon; 
typedef std::list<Polygon> PolygonList; 

// List of all our polygons 
PolygonList polygonList; 

Я создал метод ниже, чтобы попытаться удалить ближайшую точку из (x, y), проверив все мои полигоны в моем списке polygonList.

void deleteNearestPoint(int x, int y)
{
    y = screenHeight - y;

    Polygon &closestPolygon = polygonList.front();
    Polygon::iterator closestPoint = closestPolygon.begin();

    float closestDistance = sqrt(pow(x - closestPoint->x, 2) + pow(y - closestPoint->y, 2));

    // Search PolygonList
    PolygonList::iterator listIter;
    Polygon::iterator iter;

    for(listIter = polygonList.begin(); listIter != polygonList.end(); listIter++)
    {
        Polygon &tempPolygon = *listIter;

        for(iter = tempPolygon.begin(); iter != tempPolygon.end(); iter++)
        {
            const float distance = sqrt(pow(x - iter->x, 2) + pow(y - iter->y, 2));

            if (distance < closestDistance)
            {
                closestPolygon = *listIter;
                closestPoint = iter;
                closestDistance = distance;
            }
        }

    }

    closestPolygon.erase(closestPoint);

    redraw();
}

Однако где-то у меня есть указатель или ссылочная переменная, которая меня облажает. Этот код компилируется, но действует очень странным образом.

Я написал оператор отладки и допустим, что в моем списке многоугольников есть 3 типа:

Полигон #: 0
Точка: (448, 43)
Точка: (469, 177)
Точка: (374, 123)
№ полигона: 1
Точка: (295, 360)
Точка: (422, 350)
Точка: (315, 266)
Точка: (295, 360)
№ полигона: 2
Точка: (143, 202)
Точка: (301, 203)
Точка: (222, 100)
Точка: (143, 202)

Теперь, допустим, я пытаюсь использовать функцию удаления, давая ей значение х / у, близкое к точке 422, 350. Желаемым результатом будет простое удаление этой точки (422, 350) из полигона # 1, но вместо этого я получаю это :

Полигон #: 0
Точка: (295, 360)
Точка: (422, 350)
Точка: (315, 266)
Точка: (295, 360)
№ полигона: 1
Точка: (295, 360)
Точка: (315, 266)
Точка: (295, 360)
№ полигона: 2
Точка: (143, 202)
Точка: (301, 203)
Точка: (222, 100)
Точка: (143, 202)

Он действительно удалил (422, 350), но у него также есть странный побочный эффект перезаписи Polygon # 0 до того, что было у Polygon # 1 до удаления его точки.

Я знаю, что неправильно использую указатель или ссылку в моем методе. Может кто-то указать, что я мог бы сделать, что вызывает это? Я думаю, это потому, что мой & closestPolygon объявлен как ссылка, но я получаю ошибки компиляции, если я пытаюсь установить его как что-либо еще.

Ответы [ 5 ]

6 голосов
/ 13 февраля 2009

К сожалению, вы не можете перепривязать ссылку, то есть эту строку:

closestPolygon = * listIter;

скопирует *listIter в closestPolygon, а не перенаправит ссылку на *listIter.

Редактировать: Чтобы сделать то, что вы хотите, вы должны использовать PolygonList::iterator вместо Polygon & и соответственно изменить код.

4 голосов
/ 13 февраля 2009

В других ответах указано, что вызвало ошибку. В качестве общего совета я бы предложил не использовать ссылки, кроме как в аргументах функции. Семантика сбивает с толку и того, кто попытается прочитать ваш код. Попробуйте переписать что-то вроде этого (я не тестировал код):

void deleteNearestPoint(int x, int y)
{
    y = screenHeight - y;

    PolygonList::iterator closestPolygon = polygonList.begin();
    Polygon::iterator closestPoint = closestPolygon->begin();

    float closestDistance = sqrt(pow(x - closestPoint->x, 2) + pow(y - closestPoint->y, 2));

    // Search PolygonList
    PolygonList::iterator listIter;
    Polygon::iterator iter;

    for(listIter = polygonList.begin(); listIter != polygonList.end(); listIter++)
    {
        for(iter = listIter->begin(); iter != listIter->end(); iter++)
        {
            const float distance = sqrt(pow(x - iter->x, 2) + pow(y - iter->y, 2));

            if (distance < closestDistance)
            {
                closestPolygon = listIter;
                closestPoint = iter;
                closestDistance = distance;
            }
        }

    }

    closestPolygon->erase(closestPoint);

    redraw();
}
3 голосов
/ 13 февраля 2009

Вы не можете назначить ссылку.
Это основное отличие между ссылками в C ++ и ссылками в C # и т.п. Как только вы инициализируете ссылочную переменную с объектом, эта переменная становится псевдонимом этого объекта. присвоение ссылочной переменной эквивалентно присвоению исходному объекту. Имея это в виду, эта строка:

closestPolygon = *listIter;

означает, что вы перезаписываете ранее найденный ближайший полигон текущим. Это также соответствует полученному результату. Я предлагаю вам использовать указатели вместо ссылки для этого метода.

Кроме того, как заметил кто-то другой, использование pow(... , 2) крайне расточительно. еще лучше напишите что-то вроде этого:

x = a - b;
xsquare = x * x;

РЕДАКТИРОВАТЬ: Написание этого с указателями начнется с чего-то вроде:

void deleteNearestPoint(int x, int y)
{
    y = screenHeight - y;

    Polygon *closestPolygon = &polygonList.front();
    Polygon::iterator closestPoint = closestPolygon.begin();
2 голосов
/ 13 февраля 2009
closestPolygon = *listIter;

Вместо этого вызовет operator = () для объекта, на который указывает ссылка, поэтому он заменит первый многоугольник вторым.

Вместо этого объявите closestPolygon как указатель (который может указывать на разные объекты даже после его объявления)

Polygon *closestPolygon = &(polygonList.front());
...
closestPolygon = &(*listIter);
1 голос
/ 13 февраля 2009

Я вижу, что на ваш вопрос уже был дан ответ - я добавлю свои 2 цента и предложу вам сделать расстояние методом Point, чтобы сохранить дублирующий код.

Как уже говорили другие, вы также можете использовать метод squareDistance (x, y), если это облегчит вам жизнь.

Любой из них может быть встроен, если вы беспокоитесь о накладных расходах при вызове функции.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...