Attribut manchmal (?!) undefiniert



  • Hi,

    ich entwickle nach einigen Jährchen mal wieder etwas in C++. Als Einstieg hab ich mir 4 Gewinnt ausgesucht.

    Ich habe jetzt folgendes Problem:

    //Die Klasse Feld wird genutzt, um Feld-Objekte zu erzeugen.
    //Objekte der Klasse Feld sind von TLabel abgeleitet.
    //Beim Anklicken verändern sie ihr Aussehen.
    class Feld : public TLabel
    {
       private:
         Spieler* belongsToPlayer;              //Besitzer des Spielfelds
         unsigned int x,y;                      //Koordinaten
    
       public:
         __fastcall Feld(AnsiString name,       //Name des Felds
              TComponent* Owner,                //Objektbesitzer
              TWinControl* parent,              //Elternelement
              unsigned int width,               //Breite
              unsigned int height,              //Höhe
              unsigned int top,                 //y-Koordinate
              unsigned int left,                //x-Koordinate
              TColor cl,                        //Feldfarbe
              unsigned int _x,                  //Spalte
              unsigned int _y)                  //Reihe
         : TLabel(Owner)                        //Konstrukturaufruf von TLabel
         {
           this->Color = cl;
           this->AutoSize = false;              //Das Feld soll sich nicht dem Inhalt anpassen
           this->Font->Color = clWhite;
           this->Parent = parent;
           this->Caption = " ";                 //Auf dem Feld soll nichts stehen
           this->ShowHint = true;               //Hinweis beim Überfahren mit der Maus: ja
           this->Hint = "Leeres Feld";          //Standarttext des Hinweises
           this->Top = top;
           this->Left = left;
           this->Width = width;
           this->Height = height;
           this->x = _x;
           this->y = _y;
           this->Name = name;
           this->belongsToPlayer = NULL;        //Anfangs besitzerlos
           this->Layout = tlCenter;             //in y-Richtung zentrieren
           this->Alignment = taCenter;          //in x-Richtung zentrieren
           this->Font->Size = 10;
           this->Font->Style = TFontStyles()<< fsBold;   //Fette Schrift
         }
    
         unsigned int getX()
         {
           return this->x;
         }
    
         unsigned int getY()
         {
           return this->y;
         }
    

    Das ist der relavante Teil der Klasse.
    Beim Aufruf der Methode getX() (aber auch bei getY()) erhalte ich oft (aber nicht immer) die Meldung: Zugriffsverletzung (E_AccessViolation) an Adresse 0013h
    Markiert wird dann jeweils die return-Zeile rot.

    Ich rufe die Methoden folgendermaßen auf

    this->getHighestField(feld->getX());
    

    Habt ihr eine Ahnung, woran das liegen könnte?
    Das Attribut MUSS doch theoretisch lesbar sein, ich weise im Konstruktor ja einen Wert zu...

    MfG
    Simon



  • Hallo

    Der Zeiger feld ist vermutlich nicht mit der Adresse einer gültigen Instanz belegt (Vielleicht sogar this). Mit Attributen oder Konstruktoren hat das dann nichts zu tun, sondern mit falschem dynamischem Speichermanagment. An dieser Stelle merkt Windows zur Laufzeit den Fehler, aber der eigentliche Grund kann ganz wo anders liegen, vermutlich auch außerhalb des hier gezeigten Ausschnittes. Benutz den Debugger um die Stelle im Quellcode zu finden.

    bis bald
    akari



  • Danke für deine Antwort.

    Das heißt dann wohl lange Fehlersuche 😞

    Aber eigentlich kann ich mir nicht vorstellen, dass das Feld-Objekt gar nicht existiert. Denn direkt nach dem Start der Anwendung wird es instanziiert.

    Wie könnte es denn "verloren" gehen? Ich lösche es nirgends...

    MfG
    Simon



  • Hallo

    Das ist für uns hier ohne kompletten relevanten Code nicht übersehbar. Möglicherweise ist feld gar nicht mit einer korrekten Speicheradresse belegt worden. Überprüf deinen Programmfluß.

    bis bald
    akari



  • Leute, ich hab den Fehler gefunden! 🙂
    Und zwar ohne Debugger.

    // Diese Methode regelt den Spielablauf. Mit dem ersten Klick eines Spielers beginnt das Spiel.
    // Ist der zweite Spieler der PC, wird automatisch die entsprechende Methode aufgerufen.
    void __fastcall Controller::onClick(TObject *Sender)
    {
     Feld *feld = NULL;                  //Temporärer Speicher für Felder
     feld = dynamic_cast<Feld*>(Sender); //Sender-Objekt wird zu Feld-Objekt gecastet
    
     if(this->isFinished())  //Falls das Spiel beendet wurde, wird abgebrochen
     {
       return;               //Abbrechen
     }
    
     if(this->getCurrentPlayer()->getType() == "Mensch"  //Falls der Spieler ein Mensch ist
     && (Sender == NULL || feld == NULL))                //Und kein Feld angeklickt wurde
     {
       return;                                           //Abbrechen
     }
    
     this->getHighestField(feld->getX());
    
     if(this->getCurrentPlayer()->getType() == "Mensch"
        && !feld->isEmpty()) //Falls der Spieler ein Mensch ist und das Feld belegt ist
     {
       return;                         //Wird die Methode abgebrochen, da nur leere
     }                                 //Felder angeklickt werden dürfen
    
     //Sollte der aktuelle Spieler der PC sein, muss der Zug des PCs mit der Methode zugPC ausgeführt werden
     if(this->getCurrentPlayer()->getType() == "Computer" && !this->isFinished())
     {
      Sleep(300);  //PC setzt nicht sofort, sondern wartet 300ms.
    
      this->zugPC(); //Der PC führt den Zug aus
     }
     //Der aktuelle Spieler ist kein PC, sondern ein Mensch. Klick wird ausgewertet
     else if(this->getCurrentPlayer()->getType() == "Mensch" && !this->isFinished())
     {
        if(feld->isEmpty())  //Man darf nur leere Felder anklicken
        {
         feld->setColor(this->getCurrentPlayer()->getColor());  //Angeklicktes Feld einfärben
         feld->setPlayer(this->getCurrentPlayer());             //Besitzer des Felds eintragen
        }
     }
     else
     {
         ShowMessage("Der Spielertyp des aktuellen Spielers ist undefiniert. Spielabbruch");
         this->setFinished(true);   //Spiel beenden, da Fehler auftrat.
     }
    
     this->searchWinner();    //Schauen, ob es einen Gewinner gibt / Unentschieden
    
     //Nur weitermachen, wenn das Spiel nicht beendet wurde.
     if(!this->isFinished())
     {
       //Spielzähler erhöhen. Der aktuelle Spieler ist jetzt der nächste Spieler
       this->incrementCounter();
    
       //Status aktualisieren. Es wird jetzt der aktuelle (also der nächste) Spieler
       //im Status angezeigt.
       this->refreshStatus();
    
       //Diese Stelle ist sehr wichtig für den Fall, dass ein Computerspieler an der Reihe ist.
       //Der PC löst nämlich kein onClick-Event aus, deshalb machen wir das hier manuell.
       if(this->getCurrentPlayer()->getType() == "Computer")
       {
         //Hier wird das onClick-Event manuell ausgelöst (als ob der PC geklickt hätte)
         this->onClick(NULL);
       }
     }
     else
     {
       this->incrementCounter(); //Wenn Spiel beendet wurde, muss der Spielzähler
                                 //noch um 1 erhöht werden, weil er sonst den
                                 //beendenden Zug nicht enthält.
     }
    }
    

    Das Sender-Objekt war leer, wenn der PC der Gegenspieler war. Daher konnte kein getX() aufgerufen werden.
    Muss mir jetzt noch eine bessere Lösung überlegen, aber bin jetzt erstmal froh, dass ich die Ursache gefunden habe.

    MfG
    Simon
    Und danke nochmal!



  • Nach einem Cast sollte man auch prüfen ob der Cast geklappt hat. Dann gibt es auch keine so bösen Überraschungen 😉


Anmelden zum Antworten