Delphi-PRAXiS
Seite 1 von 2  1 2      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi Probleme mit FreeandNil (https://www.delphipraxis.net/108030-probleme-mit-freeandnil.html)

Maurice 6. Feb 2008 15:27


Probleme mit FreeandNil
 
Moin,
ich nehme an so einem Turnier, organisiert von der Uni Kiel teil:
http://www.informatik.uni-kiel.de/so...2008/download/ (Version B, mit Trennung der Strategie)

Da ich leider selbst nicht allzuviel Ahnung vom Programmieren habe wende ich mich an euch und zwar:

Ich lege mir in der USimpleAI ein Record an mit allen möglichen Zügen:

TMovesWithPoints = record
move : TMove;
points : TSingleScoreData;
pointscount : Integer;
stoneindex : Integer;
ChuckNorris: Integer;

Und am Ende wird der "beste" Zug aus diesem Array ausgewählt (sprich der, bei dem der Chuck Norris Wert am höchsten ist ^^). Danach will ich das Record per Freeandnil wieder freigeben, jedoch bekomme ich dann jedesmal eine Fehlermeldung vom Server "Received Null String" Nu hab ich mich schlau gemacht und mir wurde gesagt, dass das Result nicht absolut gespeichert wird, sondern als Zeiger auf den Eintrag im Record, deshalb hab ich mir den Move als solchen mit allen Daten des besten Moves neu generiert:

function Finalmove(Move: TMove): TMove;
var stone: TStone;
f1, f2: Integer;
c1,c2: TCoordinate;

begin
f1:=move.stone.getSymbol(0);
f2:=move.stone.getSymbol(1);
Stone:= TStone.Stone(f1,f2);

c1:= move.getCoordinates[0];
c2:= move.getCoordinates[1];

result:= TMove.TMove(Stone,c1,c2);
end;

Und das Ergebnis dieser Funktion wird als Result der Hauptfunktion ausgespuckt und hinterher das Record freigegeben. Gibt aber trotzdem wieder diese Fehlermeldung. Ich hab mich per F7 mal durch den Code geklickert... Man kommt dabei in die CPU Ansicht des Freeandnil befehls und bevor (!) er ganz durch ist, kommt die Fehlermeldung vom Server "Received Null String". Dabei ist es egal, ob ich den Befehl vor oder nachs result:= setze.
Deshalb wundert mich das ganze auch so, der Ausgabewert dieser Funktion wird nämlich erst in der UNetwork letztlich weggeschickt, aber bis dahin kommt er erst garnicht, wenn ich das FreeAndNil drinlasse.

Wenn ihr noch irgendwelche Infos braucht, kein Problem.

Danke schonmal für Antworten, ohne die Freigabe kann ichs ziemlich vergessen, da ich nach 10 Zügen ne Speicherausnutzung von 500MB hab...

Gruß
Maurice

Nuclear-Ping 6. Feb 2008 15:34

Re: Probleme mit FreeandNil
 
Bitte formatiere Delphi-Code mit den [ delphi ] ... [ /delphi ] Tags.

Einen Record brauchst du nicht freigeben, wenn du ihn nicht reserviert hast.

Was ist TMove? Eine Klasse? Wenn ja, mußt du in deinem Record diese auch mit MovesWithPoints.Move := TMove.Create erzeugen.

Maurice 6. Feb 2008 16:35

Re: Probleme mit FreeandNil
 
Moin,

Zitat:

Zitat von Nuclear-Ping
Bitte formatiere Delphi-Code mit den [ delphi ] ... [ /delphi ] Tags.

Wird gemacht.

Zitat:

Einen Record brauchst du nicht freigeben, wenn du ihn nicht reserviert hast.

Was ist TMove? Eine Klasse? Wenn ja, mußt du in deinem Record diese auch mit MovesWithPoints.Move := TMove.Create erzeugen.
Ist passiert, ja. Der Constructor von TMove sieht so aus:
Delphi-Quellcode:
constructor TMove.TMove( pid,ChuckNorris: Integer; st: TStone; const c1, c2: TCoordinate );
begin
  FplayerID := pid;
  Fstone := st;
  SetLength( Fcoordinates, 2 );
  Fcoordinates[0] := TCoordinate.TCoordinate( c1.x, c1.y );
  Fcoordinates[1] := TCoordinate.TCoordinate( c2.x, c2.y );
end;
Dazu:
Delphi-Quellcode:
constructor TMove.TMove( st: TStone; x1, y1, x2, y2: Integer );
begin
  FplayerID := -1;
  Fstone := st;
  SetLength( Fcoordinates, 2 );
  Fcoordinates[0] := TCoordinate.TCoordinate( x1, y1 );
  Fcoordinates[1] := TCoordinate.TCoordinate( x2, y2 );
end;
Habe jetzt etwas herausgefunden: Wenn ich nicht das Moves Record freigeben will, sondern ein anderes, was ich in der SimpleAI benutze, dann passiert folgendes:
Er geht bei dieser Funktion, aus der heraus er die SimpleAI aufruft:
Delphi-Quellcode:
function TNetwork.processMessage( handler: TMessageHandler ): Boolean;
var
  msgs: TStringList;
  serverMessage, mStr: String;
  identifier: Char;
  m: TMove;
  tmp: TBoardData;
  tmpS: TScoreData;
  i, j, number, playerNum, k: Integer;
  msg: TStringTokenizer;
  handled: Boolean;
  stones: TStoneArray;
begin
  // warte auf Servernachricht
  msgs := Fsocket.receiveLn();
  result := True;
  for k := 0 to msgs.Count - 1 do
  begin
    serverMessage := msgs[k];
    WriteLn( '> ' + serverMessage );
    msg := TStringTokenizer.TStringTokenizer( serverMessage );
    try
      handled := False;
      if ( Length( serverMessage ) > 0 ) then
      begin
        mStr := msg.nextToken();
        // lies den Nachrichtenidentifier aus
        identifier := mStr[1];
        // untersuche identifier und verarbeite entsprechende Nachricht
        case identifier of
          MESSAGE_SERVER_INITIAL:
          begin
            number := StrToInt( msg.nextToken() );
            Fboard^.playerID := number;
            handler.initialMessage( serverMessage );
            handled := True;
          end;
          MESSAGE_SERVER_STONES:
          begin
            unserializeStone( serverMessage, stones );
            handler.newStones( stones );
            handled := True;
          end;
          MESSAGE_SERVER_REQUEST_MOVE:
          begin
            Fboard^.update( serverMessage );
            m := handler.myTurn( serverMessage );
            m.playerID := Fboard^.playerID;
            Fboard^.update( m );
            sendMove( m );
            handled := True;
          end;
          MESSAGE_SERVER_ANSWER_BOARD:
          begin
            for i := 0 to 10 do
            begin
              for j := 0 to 10 do
              begin
                number := StrToInt( msg.nextToken() );
                tmp[i][j] := number;
              end;
            end;
            Fboard^.update( tmp );
            handled := True;
          end;
          MESSAGE_SERVER_ANSWER_SCORE:
          begin
            for playerNum := 0 to 1 do
            begin
              for j := 0 to 5 do
              begin
                number := StrToInt( msg.nextToken() );
                tmpS[playerNum][j] := number;
              end;
            end;
            Fboard^.updateScores( tmpS );
            handled := True;
          end;
          MESSAGE_SERVER_RESET:
          begin
            handler.reset( serverMessage );
            handled := True;
          end;
          MESSAGE_SERVER_REQUEST_CHANGE:
          begin
            if ( handler.changeRequest( serverMessage ) ) then
              mStr := MESSAGE_CLIENT_ANSWER_CHANGE + ' '
                + MESSAGE_CLIENT_ANSWER_CHANGEACCEPT
            else
              mStr := MESSAGE_CLIENT_ANSWER_CHANGE + ' '
                + MESSAGE_CLIENT_ANSWER_CHANGEREJECT;
            sendString( mStr );
            handled := True;
          end;
          MESSAGE_SERVER_TERMINATE:
          begin
            disconnect();
            handler.terminate( serverMessage );
            handled := True;
          end;
        end;
      end;
      result := handled and result;
    finally
      FreeAndNil( msg );
    end;
  end;
  FreeAndNil( msgs );
end;
normalerweise auf diese Zeile: m := handler.myTurn( serverMessage );
Wenn ich allerdings den Freeandnilbefehl drinhab, dann geht er nach der SimpleAI direkt auf diese: result := handled and result;

Er überspringt also das senden und deshalb gibts die Fehlermeldung, es wird also irgendwo in dem Grundgerüst des Clients n Fehler sein. Wenn irgendwer da die Lust zu hat, sich das mal anzugucken, dem kann ich meinen aktuellen Client gerne mal schicken, ansonsten werde ich denke ich das Record so umschreiben müssen, dass es nurnoch Integerwerte enthält, die er dann automatisch wieder freigibt.

Gruß
Maurice

Nuclear-Ping 7. Feb 2008 00:28

Re: Probleme mit FreeandNil
 
Sicher, dass "constructor TMove.TMove" funktioniert? Kenne nur die "constructor TMove.Create"-Variante.

Den Code hab ich mir da nicht angeguckt. Aber du versuchst wohl irgendwas freizugeben, was du nicht / falsch reserviert hast.

Sidorion 7. Feb 2008 09:29

Re: Probleme mit FreeandNil
 
Der Konstructor funktioniert schon, ausser dass mann dann TMove.TMove schreiben muss anstelle von TMove.Create.

@FreeAndNil: Probier doch mal anstelle FreeAndNil(Obj); lieber Obj.Free; Obj:=Nil; zu schreiben.
FreeAndNil heisst nämlich falsch. Es müsste NilAndFree heissen, weil innerhalb dieser funktion wird das übergebene Objekt erst gemerkt, dann der übergebene Zeiger genilt und danach erst das Objekt freigegeben. Hat bei mir in der Firma schon zu langen debugorgien geführt.

Muetze1 7. Feb 2008 11:57

Re: Probleme mit FreeandNil
 
Zitat:

Zitat von Sidorion
@FreeAndNil: Probier doch mal anstelle FreeAndNil(Obj); lieber Obj.Free; Obj:=Nil; zu schreiben.
FreeAndNil heisst nämlich falsch. Es müsste NilAndFree heissen, weil innerhalb dieser funktion wird das übergebene Objekt erst gemerkt, dann der übergebene Zeiger genilt und danach erst das Objekt freigegeben. Hat bei mir in der Firma schon zu langen debugorgien geführt.

Und was sollte das für einen Unterschied machen? Hintergrund ist einfach nur, dass die Variable definitv auf NIL gesetzt wird, auch wenn der Destructor Aufruf eine Exception hervor bringt. Der Code ist in der Implementierung einer Sicherheitsfrage geschuldet, aber ich erkenne keinen Grund, warum dies in "Debugorgien" enden sollte bzw. was daran falsch sein sollte...

peschai 8. Feb 2008 05:55

Re: Probleme mit FreeandNil
 
Zitat:

constructor TMove.TMove(...
1.) Ein Constructor sollte/darf NIEMALS wie die Klasse selber lauten :evil:
2.) FreeAndNil setzt Nachkommen von TObject voraus ... Ist diese Voraussetzung bei dir gegeben ?(Vermisse Inherited in deinem Constructor)
3.) Schliesse mich auch Muetze1 an...

mkinzler 8. Feb 2008 06:56

Re: Probleme mit FreeandNil
 
Zitat:

Ein Constructor sollte/darf NIEMALS wie die Klasse selber lauten Evil or Very Mad
Verboten ist das nicht, man sollte sich aber an die Vorgaben von Delphi halten und ihn Create nennen. Dann ist auch die Weiterleitung and den Konstruktor der Superklasse einfacher/übersichtlicher.
Zitat:

FreeAndNil setzt Nachkommen von TObject voraus ... Ist diese Voraussetzung bei dir gegeben ?
Ja, denn in Delphi erbt jede Klasse von TObject

peschai 8. Feb 2008 12:01

Re: Probleme mit FreeandNil
 
@mkinzler:
Das bedeuted, daß
Delphi-Quellcode:
....=Class
dasselbe ist wie
Delphi-Quellcode:
...=Class(tObject)
?

DeddyH 8. Feb 2008 12:16

Re: Probleme mit FreeandNil
 
Ja


Alle Zeitangaben in WEZ +1. Es ist jetzt 15:36 Uhr.
Seite 1 von 2  1 2      

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz