2009-02-13 10 views
6

Última pregunta para esta noche, lo prometo. Estos indicadores me están causando un gran dolor de cabeza.¿Cómo estoy sobrescribiendo accidentalmente al hacer referencia a estos punteros?

que tienen un std :: lista <Point> llamado polígono y un std :: lista de polígonos define como:

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

// List of all our polygons 
PolygonList polygonList; 

creé el método siguiente para intentar eliminar el punto más cercano de una (x, y), comprobando todos mis polígonos dentro de mi 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(); 
} 

Sin embargo, en algún lugar que tienen una variable puntero o una referencia mí meter la pata. Este código se compila pero actúa de una manera muy extraña.

He escrito una declaración de depuración y Digamos que tengo 3 polígonos en mi lista de polígonos de este modo:

Polígono #: 0
Point: (448, 43)
Point: (469 , 177)
Point: (374, 123)
Polygon #: 1
Point: (295, 360)
Point: (422, 350)
Point: (315, 266)
Point: (295, 360)
Polygon #: 2
Point: (143, 202)
Point: (301, 203)
Point: (222, 100)
Point: (143, 202)

Ahora, digamos que tratar de utilizar la función de eliminación dándole un x/y cerca del punto 422, 350 el resultado deseado sería simplemente borrar ese punto (422, 350) de Polígono # 1, pero en lugar de Entiendo esto:

Polygon #: 0
Point: (295, 360)
Point: (422, 350)
Point: (315, 266)
Point: (295, 360)
Polygon #: 1
Point: (295, 360)
Point: (315, 266)
Point: (295, 360)
Polygon #: 2
Point: (143, 202)
Point: (301, 203)
Point: (222, 100)
Punto: (1 43, 202)

Sí eliminó (422, 350) pero también tiene el extraño efecto secundario de sobrescribir el Polígono # 0 a lo que era el Polígono # 1 antes de la eliminación de su punto.

Sé que estoy usando un puntero o una referencia incorrectamente en mi método. ¿Puede alguien señalar lo que podría estar haciendo que está causando esto? Creo que es porque mi &Polygon más cercano está declarado como referencia, pero obtengo errores de compilación si intento establecerlo como cualquier otra cosa.

+0

Como acotación al margen, y es de esperar con un poco de valor educativo: trabajar con el cuadrado de la distancia que le ahorrará sqrt caro() llama. Además, pow() es bastante caro; ya que solo está usando números enteros, es mejor que escriba su propia función square(). – Thomas

Respuesta

4

Otras respuestas han señalado qué causó el error. Como consejo general, sugeriría no usar referencias, excepto en los argumentos de función. La semántica es confusa, también para alguien que intentará leer su código. Intente volver a escribir a algo como esto (no he probado el código):

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(); 
} 
+0

Buena respuesta Dani van der meer – mmcdole

+0

Sí, gracias. Tuve varias buenas respuestas, pero le agradezco que me muestre algunas de las otras cosas que hizo en este ejemplo de código también. Como usar el puntero del primer iterador para repetir el segundo ciclo, etc. Funcionó como un amuleto. – KingNestor

3

No se puede asignar a una referencia.
Esta es una diferencia principal entre referencias en C++ y referencias en C# y similares. Una vez que inicializa una variable de referencia con un objeto, esa variable se convierte en un alias para ese objeto. asignar a la variable de referencia equivale a asignar al objeto original. Con esto en mente, esta línea:

closestPolygon = *listIter; 

significa que se desea sobreescribir el polígono más cercano previamente encontrado con la actual. Esto también es consistente con el resultado que está obteniendo. Sugiero que use punteros en lugar de referencia para este método.

Además, como lo ha señalado otra persona, usar pow(... , 2) es extremadamente inútil. mejor aún escribir algo como esto:

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

EDIT: Escribir este con los punteros se iniciará con algo así:

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

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

¿Puedes elaborar un poco? Intenté cambiar todo a punteros y fallé. – KingNestor

+0

El pow (..., 2) está bien, al menos en tierra C++. Se compila para lo mismo, ya que hay una sobrecarga para (float, int) y (double, int). – MSN

+0

@MSN, aun así, es probable que todavía tenga la sobrecarga de la llamada a la función. – shoosh

6

Por desgracia, no se puede volver a enlazar una referencia, es decir, esta línea:

closestPolygon = * listIter;

copiará *listIter en closestPolygon, no vuelve a enlazar con la referencia a *listIter.

Editar: Para hacer lo que desee, debe usar PolygonList::iterator en lugar de Polygon & y ajustar el código en consecuencia.

2
closestPolygon = *listIter; 

en su lugar llamar operador =() en el objeto señalado por la referencia, por lo que se sobreponen a los primero polígono con el segundo.

Declarar closestPolygon como un puntero en lugar (que puede apuntando a diferentes objetos, incluso después de su declaración)

Polygon *closestPolygon = &(polygonList.front()); 
... 
closestPolygon = &(*listIter); 
1

veo su pregunta ya ha sido contestada - Voy a tirar mis 2 centavos en y sugiero que hagas de la distancia un método de Punto para guardar el código de duplicación.

Como otros han dicho, es posible que también desee un método de distancia cuadrada (x, y) si eso le hará la vida más fácil.

Cualquiera podría estar subrayado si le preocupa la sobrecarga de la llamada a la función.

Cuestiones relacionadas