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