Sonderbare Variabelveränderung



  • Hallo,

    ich habe ein Problem mit einer Variable die sich ohne mein gezieltes Zutun verändert.
    Ich habe ein struct Body, das eine statische Erstellfunktion Box hat, die einen Body zurückliefert. Body hat einen Pointer-Array von SubBody (weiteres struct). SubBody hat einen Vector2-Pointer-Array und einen Integer zur Zählung der Punktezahl.
    Nach dem zurückliefern lese ich den Integerwert des ersten SubBodys aus, und der hat sich aus irgend einem Grund verändert :S

    Hier der (hoffentlich) relevante Codeausschnitt:

    struct SubBody{
       Vector2 *axVertices[32];
       int iVerticeCount;
    }
    
    struct Body{
       SubBody *axSubBody[32];
       int iBodyCount;
    
       static Body Box(float x, float y, float fDensity, float fWidth, float fHeight){
          Body b;
    
          Vector2 *axVertices[4];
    
          axVertices[0]=&Vector2(-fWidth/2, -fHeight/2);
          axVertices[1]=&Vector2( fWidth/2, -fHeight/2);
          axVertices[2]=&Vector2( fWidth/2,  fHeight/2);
          axVertices[3]=&Vector2(-fWidth/2,  fHeight/2);
    
          SubBody *axSubBody[1];
    
          axSubBody[0]=&SubBody();
          axSubBody[0]->init(axVertices, 4);
    
          b.init(Vector2(x, y), fDensity, axSubBody, 1);
    
          cout << "in box: \n";
          cout << b.axSubBody << " " << b.axSubBody[0] << "\n";
          cout << "count: "<< b.axSubBody[0]->iVerticeCount << "\n";
    
          /*
          in box:
          0015F1E4 0015EFD0
          count: 4
          */
    
          return b;
       }
    }
    
    int main() {
       Body b=Body::Box(0, 0, 0.1, 20, 20);
    
       cout << "in main: \n";
       cout << b.axSubBody << " " << b.axSubBody[0] << "\n";
       cout << "count: " << b.axSubBody[0]->iVerticeCount << "\n";
    
       /*
       in box:
       0015F45C 0015EFD0
       count: -858993460
       */
    
       system("PAUSE");
       return EXIT_SUCCESS;
    }
    

    Wie ich in der Ausgabe sehe, ändert die Pointeradresse von dem SubBody-Array von 0015F1E4 zu 0015F45C, allerdings bleibt die Adresse des ersten Eintrags dieses Arrays gleich (0015EFD0). Und trotzdem ändert sich das iVerticeCount-Feld von 4 auf -85..

    Ich hoffe es kann mir jemand erklären, woran das liegt 😕 Ich bin für jegliche Hilfe dankbar,

    MfG,
    Darth



  • Darth schrieb:

    axVertices[0]=&Vector2(-fWidth/2, -fHeight/2);
          axVertices[1]=&Vector2( fWidth/2, -fHeight/2);
          axVertices[2]=&Vector2( fWidth/2,  fHeight/2);
          axVertices[3]=&Vector2(-fWidth/2,  fHeight/2);
    

    Was soll das denn werden? Du nimmst die Addresse von Rückgabeparametern? Die sind in diesem Fall doch sofort ungültig - denn das Objekt wird nicht genutzt, und daher sofort zerstört.



  • Hallo Janjan,

    Vector2 ist ein struct, und Vector2(float x, float y) ist ein zugehöriger Constructor.
    Die Membervariable "axVertices" ist ein Array von Pointern auf Vector2 Instanzen, also muss ich doch den Zeiter auf die neu erstellte Vector2-Instanz speichern? 😕
    Hab ich da etwas falsch verstanden?

    MfG,
    Darth



  • Darth schrieb:

    Hallo Janjan,

    Vector2 ist ein struct, und Vector2(float x, float y) ist ein zugehöriger Constructor.
    Die Membervariable "axVertices" ist ein Array von Pointern auf Vector2 Instanzen, also muss ich doch den Zeiter auf die neu erstellte Vector2-Instanz speichern? 😕
    Hab ich da etwas falsch verstanden?

    MfG,
    Darth

    Ja, weil das Objekt, welches du so erstellst:

    Vector2(-fWidth/2, -fHeight/2);
    

    lebt genau bis zu dem ";". Danach wird es zerstört und alles, was auf das Objekt verweist (also die Zeiger im Array) sind ungültig.

    Nimm lieber gleich die ganzen Objekte. Ändere dazu den Array Typen:

    Vector2 axVertices[32]; // ohne *
    

    und dann kannst du so (per Kopie) einfügen:

    axVertices[0] = Vector2(-fWidth/2, -fHeight/2); // ohne &
    


  • Hallo drakon,

    danke für die Erklärung, da hab ich wohl etwas ziemlich missverstanden. Ich habe die Arrays als Pointer-Arrays initialisiert, damit ich solche Vergleiche machen kann:

    Vector2 axV[10];
    Vector2 v=Vector2(10, 10);
    
    axV[0]=v;
    
    if(&v == &axV[0])
       cout << "jippi! \n";
    

    Mit deiner Methode der "Arraykopie" funktioniert zwar der Code, aber ich habe keine Möglichkeit mehr für meine Vergleiche 😕 Gibt es da keinen Weg drum herum?

    MfG,
    Darth

    [EDIT:]

    Achach, mir wurde grad erklärt dass es in c++ auch sowas wie "new" gibt, das schöne Pointer-Dinger zurückliefert, d.h ich kann weiter meine Pointer-Arrays verwenden, meine Vergleiche behalten.
    Das einzige was ich jetzt beachten muss ist, dass ich die Dinger wieder löschen muss, wenn ich sie verwerfe.



  • Überlade den Vergleichsoperator für Vector2d?


  • Mod

    Darth schrieb:

    Achach, mir wurde grad erklärt dass es in c++ auch sowas wie "new" gibt, das schöne Pointer-Dinger zurückliefert, d.h ich kann weiter meine Pointer-Arrays verwenden, meine Vergleiche behalten.
    Das einzige was ich jetzt beachten muss ist, dass ich die Dinger wieder löschen muss, wenn ich sie verwerfe.

    Leitfaden: Benutze new nur, wenn es sich a) nicht vermeiden lässt, b) du gan z sicher bist, dass new das richtige ist.

    Das trifft hier beides nicht zu.

    Vor allem: Was versprichst du dir denn davon die Adresse von zwei Objekten zu vergleichen?



  • Hallo SeppJ,

    ich verwende die new Option nur an einigen Stellen, nämlich da, wo ich die Objekte "bis in alle Ewigkeit" brauche. Ich brauche den direkten Objektvergleich (Pointer-Vergleich) bei Dingen wie Entfernen (entferne *diesen Vektor2 aus der Liste -> Pointer-Vergleich).
    Wahrscheinlich gibt es schönere Möglichkeiten den Code aufzubauen, dass ich das Array so baue wie drakon mir riet, und die Pointer nur in den Funktionen neu erstelle, wo sie tatsächlich gebraucht werden (das sind tatsächlich nur einige wenige), aber wahrscheinlich bin ich ein wenig zu Java verwöhnt (da gibt es nur Referenzen, also kann ich Objekt1=Objekt2, Objekt2==Objekt2 ganz einfach versuchen - in c++ gäbe es da ja eine Kopie und dann ein false).

    Aber danke für den Leitfaden, ich werde meinen Code nochmal durchgehen und sehen, ob sich das new nicht doch irgendwo noch ersetzen lässt. (Leider ist das Ding derart riesig (und unübersichtlich -.-) dass jede Änderung von Pointer zu irgendwas eine halbe Stunde Anpassung nach sich zieht..)

    Danke für deinen Input,
    MfG,
    Darth



  • Darth schrieb:

    Ich brauche den direkten Objektvergleich (Pointer-Vergleich) bei Dingen wie Entfernen (entferne *diesen Vektor2 aus der Liste -> Pointer-Vergleich).

    Warum? Wieso reicht es nicht, wenn zwei Objekte identisch sind? Du kannst dann in der Liste nach dem Objekt suchen und es gegebenenfalls entfernen. Mit std::set geht sowas besonders einfach.



  • Hallo Nexus,

    falls du mit "identisch" meinst, dass sie die gleichen Einträge haben, dann: nein. Es kann theoretisch vorkommen, dass mehrere Vektoren an der selben Position sind, die aber nicht die gleichen sind (also doppelt vorkommen). Ausserdem ist es "unmöglich" direktvergleiche unter Floats zu machen, man müsste das wohl mit einer Epsilon-Umgebung umgehen.
    Was ich natürlich machen könnte, wäre direkt über die Indizes zu arbeiten, aber das erscheint mir nicht sehr benutzerfreundlich.
    Aber es scheint mir, dass der "new"-Operator ziemlich verpönt ist 🙂 darum werde ich mir nochmal überlegen, ob das nicht irgendwie zu verbessern ist.

    MfG,
    Darth

    [Edit]

    Ich habe mir den Code und seine Funktionsweise nochmal genauer angesehen, und es müsste eigentlich ohne die Pointersache gehen. Also habe ich den == Operator überladen (wie gesagt mit Epsilon-Umgebung), jetzt haben zwar einige Funktionen ein Problem (weil sie eben nichtmehr überprüfen können, ob es der gleiche Vektor ist, sondern nur einer am selben Ort), aber das sollte ich Umgehen können.
    Ich danke nochmal für die Anregungen und Bemühungen eurerseits.



  • Du hast einfach sonst irgendwo ein Denkproblem.
    Wenn du aus einem dynamischen Container Objekte löschen willst, dann kannst du da schon Zeiger drin speichern. Allerdings müssen dann die Objekte irgendwo anderst gelegen sein.

    Wenn du allerdings das ganze Objekt im Container drin speicherst (wie ich vorgeschlagen habe), dann sind das sozusagen die "aktiven" Objekte. Dann weisst du allerdings immer mit welchem Objekt du arbeitest und kannst es dementsprechend auch löschen.

    Du hast schon Recht, dass ein direkter Vergleich der Werte keinen Sinn macht in diesem Falle, aber macht dir einfach klar, dass es gar nicht nötig ist.

    Achja und new ist nicht verpönt, sondern wird eben zu oft eingesetzt (an den falschen Orten). Kommt wohl von Java her.


Anmelden zum Antworten