2009-02-13 10 views
6

Ultima domanda per stasera, lo prometto. Questi suggerimenti mi stanno dando un forte mal di testa.Come faccio a sovrascrivere accidentalmente quando faccio riferimento a questi puntatori?

Ho uno std :: list <Point> chiamato poligono e uno std :: elenco di poligoni definito come:

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

// List of all our polygons 
PolygonList polygonList; 

ho creato il metodo seguito per tentare di eliminare il punto più vicino da un (x, y), controllando tutti i miei poligoni nella mia lista poligonali.

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

Tuttavia, da qualche parte ho un puntatore o una variabile di riferimento che mi incasina. Questo codice compila ma agisce in un modo molto strano.

ho scritto una dichiarazione di debug e permette di dire che ho 3 poligoni nella mia lista di poligoni in questo modo:

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

Ora, consente di dire che cercare di utilizzare la funzione di eliminazione dandogli un x/y vicino al punto 422, 350 il risultato desiderato sarebbe semplicemente cancellando quel punto (422, 350) dal poligono # 1 ma invece ottengo questo:

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

Cancellato (422, 350) ma ha anche lo strano effetto collaterale di sovrascrivere Poligono # 0 a quello che Poligono # 1 era prima dell'eliminazione del suo punto.

So che sto usando un puntatore o riferimento in modo errato nel mio metodo. Qualcuno può far notare quello che potrei fare che sta causando questo? Penso che sia perché il mio & closestPolygon è dichiarato come riferimento, ma ottengo errori di compilazione se provo a impostarlo come qualsiasi altra cosa.

+0

Per inciso, e, auspicabilmente, con un valore educativo: lavorare con quadrato della distanza vi farà risparmiare costoso sqrt() chiama. Inoltre, pow() è piuttosto costoso; dal momento che utilizzi solo numeri interi, è meglio scrivere la tua funzione square(). – Thomas

risposta

4

Altre risposte hanno indicato cosa ha causato l'errore. Come consiglio generale suggerirei di non usare riferimenti tranne che in argomenti di funzione. La semantica è confusa, anche per qualcuno che proverà a leggere il tuo codice. Provare a riscrivere a qualcosa di simile (non ho la prova il codice):

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

Bella risposta Dani van der meer – mmcdole

+0

Sì, grazie. Ho avuto parecchie buone risposte ma apprezzo che tu mi abbia mostrato alcune delle altre cose che hai fatto in questo esempio di codice. Come usare il primo puntatore iteratore per iterare il secondo ciclo, ecc. Funzionato come un incantesimo. – KingNestor

3

Non è possibile assegnare a un riferimento.
Questa è una differenza principale tra riferimenti in C++ e riferimenti in C# e simili. Una volta inizializzata una variabile di riferimento con un oggetto, quella variabile diventa un alias per quell'oggetto. l'assegnazione alla variabile di riferimento equivale all'assegnazione all'oggetto originale. con questo in mente, questa linea:

closestPolygon = *listIter; 

significa che si sta sovrascrivendo il poligono più vicino precedentemente trovato con quella attuale. Questo è anche coerente con il risultato che stai ottenendo. Ti suggerisco di usare puntatori invece di riferimento per questo metodo.

Inoltre, come notato da qualcun altro, l'utilizzo di pow(... , 2) è estremamente dispendioso. meglio ancora scrivere qualcosa del genere:

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

EDIT: Scrivere questo con puntatori inizierà con qualcosa di simile:

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

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

Puoi approfondire un po '? Ho provato a passare tutto a dei puntatori e ho fallito. – KingNestor

+0

Il pow (..., 2) va bene, almeno in C++ land. Compila la stessa cosa poiché c'è un sovraccarico per (float, int) e (double, int). – MSN

+0

@MSN, anche così probabilmente hai ancora il sovraccarico della chiamata alla funzione. – shoosh

6

Purtroppo, non è possibile associare nuovamente un riferimento, vale a dire, questa linea:

closestPolygon = * listIter;

copierà *listIter-closestPolygon, non associare nuovamente il refernece a *listIter.

Modifica: Per fare quello che vuoi, si dovrebbe usare PolygonList::iterator invece di Polygon & e regolare il codice di conseguenza.

2
closestPolygon = *listIter; 

sarà invece chiamare operator =() sull'oggetto puntato dal riferimento, così sarà sovrascrivere il primo poligono con il secondo.

Dichiarare closestPolygon come un puntatore, invece (che può rilevare a diversi oggetti, anche dopo la sua dichiarazione)

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

vedo la tua domanda è già stato risposto - mi butto i miei 2 centesimi e suggerisci di fare della distanza un metodo di Point per salvare il codice di duplicazione.

Come altri hanno già detto, si potrebbe anche volere un metodo squareDistance (x, y) se ciò ti rendesse la vita più facile.

Entrambi potrebbero essere in linea se si è preoccupati per il sovraccarico della chiamata di funzione.

Problemi correlati