AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren

Variable als Zeiger?

Ein Thema von neomic · begonnen am 22. Sep 2007 · letzter Beitrag vom 24. Sep 2007
Antwort Antwort
Seite 1 von 2  1 2   
neomic
(Gast)

n/a Beiträge
 
#1

Variable als Zeiger?

  Alt 22. Sep 2007, 13:56
Hallo,

ich arbeite zur Zeit an einem kleinem Schulprojekt, einer Ampelkreuzung-Simulation...
Das Projekt ist Open Source und steht unter keinem Copyright. Es kann unter www.neomic.xail.net/info/Ampelkreuzung.zip
heruntergeladen werden (Code ist ausreichend kommentiert ).
Alles funktioniert so wie es soll, bis auf, dass wenn die Auto aus dem Sichtbarkeitsbereich (= der Form) verschwinden, diese auch zerstört werden sollen und der Speicher freigegeben werden soll...

Folgendes Problem:

Autos dürfen nicht aufeinanderfahren: Deshalb kennt jedes Auto, das Auto vor sich

Delphi-Quellcode:
procedure TAuto.SetzeAuto(pAuto:TAuto);
begin
        kAuto:=pAuto;
end;
Wenn kein Auto davor steht ist der Wert "nil"

Dann durch die Abfrage:

Delphi-Quellcode:
// Wenn Ampel nicht rot oder rot-gelb ist und kein Auto davor oder das Auto davor weit genug weg dann fahre!
procedure TAutoVonOben.Bewegen(Sender:TObject);
begin
        if not (((kAmpel.GetStatus=1) or (kAmpel.GetStatus=2)) and (Top=150)) and
        ((kAuto=nil) or ((kAuto<>nil) and (kAuto.Top-Width-ABSTAND>Top))) then
        Top:=Top+1;
end;
Wenn das Auto vor im "nil" ist fahre...
Aber wenn ich während der Laufzeit ein Auto zerstöre und die Variale nil setze, bleibt der Wert kAuto.Top genauso wie vor dem Zerstören bzw. es ist garnicht "nil"...

Ist es möglich, das kAuto keine Referenz oder Zeiger auf das Auto ist, sondern eine Kopie?
Wie kann ich das Problem lösen?

Ich wäre um jede Hilfe dankbar!

greeetz neomic
  Mit Zitat antworten Zitat
Dezipaitor

Registriert seit: 14. Apr 2003
Ort: Stuttgart
1.701 Beiträge
 
Delphi 7 Professional
 
#2

Re: Variable als Zeiger?

  Alt 22. Sep 2007, 14:06
Also der Zeiger an sich ist einfach eine Zahl. Die Zahl gibt ja an, wo im Speicher sich die Information zum Auto befindet. Wenn du nun diesen Zeiger kopierst, dann wird nur der Wert kopiert und du hast zwei gleiche Werte,die auf denselben Speicher zeigen. Wenn du nun einen Wert auf 0 (also nil) setzt, dann bleibt der andere Zeiger unbeheligt davon.
Wenn du nun mehrere Zeiger auf das Auto hast und du verwendest einen Zeiger, um den Speicher des Autos zu löschen, dann hast du plötzlich mehrere Zeiger, die an die alte Stelle der Autoinformation zeigen. Jetzt ist der Speicher jedoch ungültig. Das führt zu Problemen (Merkwürdiges, AV).
Es gibt eine Technik mit dem Namen Referenzzählung (Reference counting), die macht folgendes, um das Problem zu verhindern:
Das Objekt (Auto) bekommt eine Integer Variable, die angibt, wieviele Zeiger auf das Objekt zeigen. Wenn diese Variable 0 ist, dann kann das Objekt gefahrlos gelöscht werden. Wenn es größer als 0 ist, dann darf es nicht gelöscht werden.
Bei jedem Erzeugen eines Zeigers auf das Objekt, wird diese Variable um eines erhöht. Bei jedem Löschen (nil-setzen!!) eines Zeigers auf das Objekt, wird diese Variable um eins erniedrigt. Für Singlethread Programme wars das auch schon.

Eine zweite Technik (deren Namen ich vergessen habe), funktioniert so:
Es gibt nur eine Zeigervariable (Hauptzeiger), die direkt auf das Objekt zeigt. Alle neuen Zeiger zeigen auf diese Zeigervariable. Folgedessen muss diese Zeigervariable im Heap existieren (erzeugt durch GetMem oder New). Wenn man auf das Objekt zugreifen will,
dass muss man zweimal referenzieren. Zuerst den Zeiger auf den Hauptzeiger und dann darüber auf das Objekt. Alle Zeiger zeigen eben zuerst auf den Hauptzeiger. Wenn man nun das Objekt löscht, dann setzt man den Hauptzeiger auf nil (nicht FreeMem der Dispose machen!) und alle andere Zeiger zeigen dann auf nil.
Natürlich muss man diese Hauptzeiger auch irgendwann mal löschen. Mann kann sie mit der Referenzählung verwalten oder in einer List verwalten, die dann ganz zum Schluss gelöscht wird.
Christian
Windows, Tokens, Access Control List, Dateisicherheit, Desktop, Vista Elevation?
Goto: JEDI API LIB & Windows Security Code Library (JWSCL)
  Mit Zitat antworten Zitat
neomic
(Gast)

n/a Beiträge
 
#3

Re: Variable als Zeiger?

  Alt 22. Sep 2007, 14:12
Kann ich den Wert in dem Speicher nil setzen?

Ansonsten versteh ich das mit deiner vorgschlagenen Methode noch nicht so ganz: Was muss ich der Variable den zuweisen bzw wie geht das überhaupt?
  Mit Zitat antworten Zitat
Dezipaitor

Registriert seit: 14. Apr 2003
Ort: Stuttgart
1.701 Beiträge
 
Delphi 7 Professional
 
#4

Re: Variable als Zeiger?

  Alt 22. Sep 2007, 14:18
Das Problem steckt sieht doch so vereinfacht aus:
Delphi-Quellcode:
var obj1, obj2 : TAuto;
begin
  obj1 := TAuto.Create;
  obj2 := obj1; //obj2 = obj1 - obj1 und obj2 zeigen auf dasselbe Auto im Speicher
  //sind jedoch zwei verschiedene variablen, eben nur mit demselben Inhalt

  obj1.Fahre; //ok
  obj2.Fahre; //ok

  obj1.Free;
  obj1 := nil;

  if Assigned(obj1) then //False
    obj1.Fahre;
  if Assigned(obj2) then //true
    obj2.Fahre; //AV
end;
Christian
Windows, Tokens, Access Control List, Dateisicherheit, Desktop, Vista Elevation?
Goto: JEDI API LIB & Windows Security Code Library (JWSCL)
  Mit Zitat antworten Zitat
neomic
(Gast)

n/a Beiträge
 
#5

Re: Variable als Zeiger?

  Alt 22. Sep 2007, 15:16
gut, soweit habe ich das jetzt verstanden...

aber wie kann ich es erreichen, das wenn das vorherige Auto zerstört wird auch die Abfrage kAuto=nil zutrifft?
  Mit Zitat antworten Zitat
Dezipaitor

Registriert seit: 14. Apr 2003
Ort: Stuttgart
1.701 Beiträge
 
Delphi 7 Professional
 
#6

Re: Variable als Zeiger?

  Alt 22. Sep 2007, 15:30
Eine zweite Technik (deren Namen ich vergessen habe), funktioniert so:
Es gibt nur eine Zeigervariable (Hauptzeiger), die direkt auf das Objekt zeigt. Alle neuen Zeiger zeigen auf diese Zeigervariable. Folgedessen muss diese Zeigervariable im Heap existieren (erzeugt durch GetMem oder New). Wenn man auf das Objekt zugreifen will,
dass muss man zweimal referenzieren. Zuerst den Zeiger auf den Hauptzeiger und dann darüber auf das Objekt. Alle Zeiger zeigen eben zuerst auf den Hauptzeiger. Wenn man nun das Objekt löscht, dann setzt man den Hauptzeiger auf nil (nicht FreeMem der Dispose machen!) und alle andere Zeiger zeigen dann auf nil.
Natürlich muss man diese Hauptzeiger auch irgendwann mal löschen. Mann kann sie mit der Referenzählung verwalten oder in einer List verwalten, die dann ganz zum Schluss gelöscht wird.
Christian
Windows, Tokens, Access Control List, Dateisicherheit, Desktop, Vista Elevation?
Goto: JEDI API LIB & Windows Security Code Library (JWSCL)
  Mit Zitat antworten Zitat
Benutzerbild von Khabarakh
Khabarakh

Registriert seit: 18. Aug 2004
Ort: Brackenheim VS08 Pro
2.876 Beiträge
 
#7

Re: Variable als Zeiger?

  Alt 22. Sep 2007, 16:01
Am einfachsten zu realisieren wäre wohl, dass jedes Auto von seinem vorausfahrenden Kollegen vor dessen Freigabe durch ein Event benachrichtigt wird und so sein Feld auf nil setzen kann. Man könnte der Auto-Klasse natürlich statt dem Event auch eine Referenz auf das hinterherfahrende Auto geben, aber solange kein Rückspiegel eingebaut wird ^^, ist diese Information ansonsten unnütz und das Event damit sauberer.
Sebastian
Moderator in der EE
  Mit Zitat antworten Zitat
neomic
(Gast)

n/a Beiträge
 
#8

Re: Variable als Zeiger?

  Alt 23. Sep 2007, 12:21
Aktuell habe ich eine (recht) einfache Möglichkeit gefunden:

Alles spielt sich jetzt eigentlich nur in der zweiten for-Schleife ab:

Delphi-Quellcode:
procedure TSteuerung.Aufraeumen();
var i,h,j:Integer;
begin
        for i:=0 to 3 do
        for h:=0 to (Length(hAuto[i])-1) do
        begin
                if hAuto[i][h].IstAusDemBild then
                begin
                        // Auto zerstören
                        hAuto[i][h].Destroy;

                        // Array Indizes verschieben und Array verkürzen
                        for j:=h to (Length(hAuto[i])-2) do hAuto[i][j]:=hAuto[i][j+1];
                        SetLength(hAuto[i],Length(hAuto[i])-2);

                        // Vordermann löschen
                        if h>0 then hAuto[i][h-1].SetzeAuto(nil);
                end;
        end;
end;
Der Code müsste von der Logik her richtig sein, aber ich bekomme nen RangeCheck Error (keine AV mehr *juhu*)

Einer ne Idee?
  Mit Zitat antworten Zitat
Hawkeye219

Registriert seit: 18. Feb 2006
Ort: Stolberg
2.227 Beiträge
 
Delphi 2010 Professional
 
#9

Re: Variable als Zeiger?

  Alt 23. Sep 2007, 13:49
Hi,

Zitat:
SetLength(hAuto[i],Length(hAuto[i])-2);
Das Verkürzen des Arrays innerhalb der Schleife führt letztlich zum Fehler. Die Schleifengrenzen werden nur einmal vor dem Eintritt in den Schleifenkörper berechnet, nach dem Verkürzen des Arrays greifst du somit zum Schluß auf nicht mehr vorhandene Elemente zu. Lasse die h-Schleife einfach rückwärts laufen.

Warum arbeitest du eigentlich mit dynamischen Arrays? Delphi bietet mit Delphi-Referenz durchsuchenTObjectList ein Listenobjekt an, das bereits Methoden zum Einfügen und Löschen von Elementen enthält.

Die Freigabe eines Objekts sollte mit der Methode Delphi-Referenz durchsuchenTObject.Free erfolgen und nicht mit TObject.Destroy.

Die Funktion Delphi-Referenz durchsuchenHigh liefert dir den höchsten Index in einem Array.

Gruß Hawkeye
  Mit Zitat antworten Zitat
neomic
(Gast)

n/a Beiträge
 
#10

Re: Variable als Zeiger?

  Alt 23. Sep 2007, 16:13
Ich finde die Idee gut...

Aber ich habe noch nen paar Probleme mit dem umsetzen:

Delphi-Quellcode:
procedure TSteuerung.NeuesAuto(pArt:Integer);
var Auto:TAuto;
begin
        // Auto erstellen
        case pArt of
                0:Auto:=TAutoVonUnten.Create(kForm,hAmpel[pArt]);
                1:Auto:=TAutoVonRechts.Create(kForm,hAmpel[pArt]);
                2:Auto:=TAutoVonOben.Create(kForm,hAmpel[pArt]);
                3:Auto:=TAutoVonLinks.Create(kForm,hAmpel[pArt]);
        end;

        // Auto zuweisen
        hAuto[pArt].Add(Auto);

        // Vordermann zuweisen
        if hAuto[pArt].Count>0 then
        hAuto[pArt].Last.SetzeAuto(hAuto[pArt].Items[hAuto[pArt].Count-1])
        else hAuto[pArt].Last.SetzeAuto(nil);
end;
Der erkennt hAuto[pArt].Last nicht als TAuto ("Undeclared identifier: 'SetzeAuto'")

Was kann ich tun?


edit: Oh ich glaub ich hab vergessen zu casten


edit2: Soweit ans laufen bekommen, nur das SetzeAuto immer nil zuweißt...

Delphi-Quellcode:
procedure TSteuerung.NeuesAuto(pArt:Integer);
var Auto,Auto2:TAuto;
var i:Integer;
begin
        // Auto erstellen
        case pArt of
                0:Auto:=TAutoVonUnten.Create(kForm,hAmpel[pArt]);
                1:Auto:=TAutoVonRechts.Create(kForm,hAmpel[pArt]);
                2:Auto:=TAutoVonOben.Create(kForm,hAmpel[pArt]);
                3:Auto:=TAutoVonLinks.Create(kForm,hAmpel[pArt]);
        end;

        // Auto zuweisen
        i:=hAuto[pArt].Add(Auto);

        // Vordermann suchen
        if i>0 then Auto2:=TAuto(hAuto[pArt].Items[i-1])
        else Auto2:=nil;

        // Vordermann zuweisen
        TAuto(hAuto[pArt].Items[i]).SetzeAuto(Auto2);
end;

Sieht einer den Fehler? o.0
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 1 von 2  1 2   

Themen-Optionen Thema durchsuchen
Thema durchsuchen:

Erweiterte Suche
Ansicht

Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 21:33 Uhr.
Powered by vBulletin® Copyright ©2000 - 2023, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2021 by Daniel R. Wolf