Autor |
Beitrag |
CoWa
      
Beiträge: 17
Windows XP Embedded
|
Verfasst: Do 21.08.08 14:41
Hallo,
Verwendete Delphiversion: 5
Wenn ich auf den Reboot Button Klicke bekomme ich eine Zugriffsverletzung.
Delphi-Quelltext 1: 2: 3: 4: 5: 6:
| procedure KeyboardClose(); begin Form1.mfSoftkeysControl1.ClosePage; Form1.mfSoftkeysControl1.Destroy; Form1.mfSoftkeysControl1.free; end; |
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8:
| procedure TForm1.BTNRebootClick(Sender: TObject); begin
KeyboardClose; ShellExecute(0, 'open', 'shutdown.exe', '-r -f -t 0', 'C:\WINDOWS\SYSTEM32\', SW_SHOWNORMAL); Form1.Close;
end; |
Wenn ich nur so einen Neustart erzwinge ohne die Form zu schließen bekomme ich die Fehlermeldung das eine Komponente (mfSoftkeysControl1) nicht beendet wurde.
Ideen wie ich das besser lösen kann?
Gruß CoWa
|
|
Martin1966
      
Beiträge: 1068
Win 2000, Win XP
Delphi 7, Delphi 2005
|
Verfasst: Do 21.08.08 14:44
Keine Ahnung was die Komponente macht aber pack auf jeden Fall das Destroy raus...
Delphi-Quelltext 1: 2: 3: 4: 5:
| procedure KeyboardClose(); begin Form1.mfSoftkeysControl1.ClosePage; Form1.mfSoftkeysControl1.free; end; |
Der Aufruf von Free ruft nämlich intern den Destruktor selbst auf.
Lg, Martin
_________________ Ein Nutzer der Ecke
|
|
Boldar
      
Beiträge: 1555
Erhaltene Danke: 70
Win7 Enterprise 64bit, Win XP SP2
Turbo Delphi
|
Verfasst: Do 21.08.08 14:44
|
|
Martin1966
      
Beiträge: 1068
Win 2000, Win XP
Delphi 7, Delphi 2005
|
Verfasst: Do 21.08.08 14:45
Boldar hat folgendes geschrieben: | Niemals free und destroy gleichzeitig aufrufen! |
Soweit ich weiß sollte man NUR destroy nie aufrufen!
_________________ Ein Nutzer der Ecke
|
|
Boldar
      
Beiträge: 1555
Erhaltene Danke: 70
Win7 Enterprise 64bit, Win XP SP2
Turbo Delphi
|
Verfasst: Do 21.08.08 14:50
Martin1966 hat folgendes geschrieben: | Boldar hat folgendes geschrieben: | Niemals free und destroy gleichzeitig aufrufen! |
Soweit ich weiß sollte man NUR destroy nie aufrufen! |
Wenn du destroy aufrufst, wird intern schon free aufgerufen. Wenn du dann nochmal free aufrufst, ist es einmal zu viel!
|
|
Martin1966
      
Beiträge: 1068
Win 2000, Win XP
Delphi 7, Delphi 2005
|
Verfasst: Do 21.08.08 14:53
Boldar hat folgendes geschrieben: | Wenn du destroy aufrufst, wird intern schon free aufgerufen. |
Nein, eigentlich nicht.
Wenn man Free aufruft wird Destroy intern aufgerufen. Anders herum nicht.
Lg, Martin
_________________ Ein Nutzer der Ecke
|
|
Yogu
      
Beiträge: 2598
Erhaltene Danke: 156
Ubuntu 13.04, Win 7
C# (VS 2013)
|
Verfasst: Do 21.08.08 14:57
Free prüft das Objekt zuerst auf nil und ruft gegebenfalls Destroy auf. Deshalb gelten zwei Regeln:
- Rufe Destroy niemals selber auf - dazu ist Free da.
- Globale oder kritische Objektvariablen müssen immer entweder auf ein gültiges Objekt zeigen, oder nil sein. Andernfalls würde ein Free auch eine Zugriffsverletzung auslösen. Also: nach Free die Variable immer auf nil setzen, oder einfach gleich FreeAndNil aufrufen.
|
|
Martin1966
      
Beiträge: 1068
Win 2000, Win XP
Delphi 7, Delphi 2005
|
Verfasst: Do 21.08.08 15:06
Yogu hat folgendes geschrieben: | Rufe Destroy niemals selber auf - dazu ist Free da. |
Ja, so hab ich es ja schon geschrieben.
Yogu hat folgendes geschrieben: | Globale oder kritische Objektvariablen müssen immer entweder auf ein gültiges Objekt zeigen, oder nil sein. |
Das sehe ich nicht so. Ein Objekt das ich freigeben will sollte meiner Meinung nach nie NIL sein. Denn das würde ja bedeuten das ich entweder ein Objekt freigeben will das noch gar nicht erstellt wurde oder aber das ich ein Objekt freigeben will welches bereits freigegeben wurde. Beides ist meiner Meinung nach Fehler. Denn: Ein mal ein Objekt erzeugen heißt auch nur (genau) einmal das Objekt wieder freigeben!
Yogu hat folgendes geschrieben: | Andernfalls würde ein Free auch eine Zugriffsverletzung auslösen. Also: nach Free die Variable immer auf nil setzen, oder einfach gleich FreeAndNil aufrufen. |
Genau das soll es ja auch damit ich als Entwickler auf diesen Fehler aufmerksam werde.  FreeAndNil versteckt nur diesen Fehler.
Lg, Martin
_________________ Ein Nutzer der Ecke
|
|
Yogu
      
Beiträge: 2598
Erhaltene Danke: 156
Ubuntu 13.04, Win 7
C# (VS 2013)
|
Verfasst: Do 21.08.08 15:16
Ok, vielleicht siehst du das anders. Aber meiner Meinung nach darf ein Objekt durchaus mal nil sein, bevor ich versuche, es freigebe. Ein Beispiel:
Eine 3D-Engine, die ein Sound-Modul besitzt. Dieses wird nicht automatisch erstellt, sondern durch eine Methode. Eine zweite gibt das Modul wieder frei. Weil die Engine aber saubar geschrieben ist, wird auch beim Entfernen der Engine das Sound-Modul wieder entfernt, falls das nicht manuell geschah. Wenn es jetzt durch die Methode freigegeben wird, muss das Objekt genillt werden, um anzuzeigen, dass es nicht mehr existiert.
|
|
Martin1966
      
Beiträge: 1068
Win 2000, Win XP
Delphi 7, Delphi 2005
|
Verfasst: Do 21.08.08 15:33
Yogu hat folgendes geschrieben: | Weil die Engine aber saubar geschrieben ist, |
Da du davon ausgehst, dass der Programmierer, der die Engine verwendet, nicht sauber programmiert hat, musst du das Objekt eventl. selbst freigeben. Ok. Aber das ist denke ich ein Sonderfall. Wie du die Überprüfung machst (ob auf NIL überprüfen oder eine Boolean Variable setzen) ist dann natürlich Geschmacksache.
Lg, Martin
_________________ Ein Nutzer der Ecke
|
|
Yogu
      
Beiträge: 2598
Erhaltene Danke: 156
Ubuntu 13.04, Win 7
C# (VS 2013)
|
Verfasst: Do 21.08.08 15:43
Ok, dann eben noch ein Versuch, dich zu überzeugen: Der Programmierer will nun wissen, ob das Sound-Modul schon initialisiert wurde. Beziehungsweise noch verfügbar ist. Wenn das Modul einfach freigegeben wurde, liefert Assigned(SoundModule) True. Er weiß also nicht, ob er auf das Modul zugreifen darf oder nicht. Bevor du mir jetzt mit einer Boolean-Variable kommst: Wozu eine neue Variable vereinbaren, wo wir doch schon eine haben? Das ist nur eine zusätzliche Fehlerquelle, denn wenn die beiden widersprüchlich sind, dann ist es aus mit der Kontrolle.
|
|
Martin1966
      
Beiträge: 1068
Win 2000, Win XP
Delphi 7, Delphi 2005
|
Verfasst: Do 21.08.08 15:54
Ich hatte doch schon angedeutet, dass es bei Bibliotheken eventl. Sinn machen könnte.
Zitat: | Der Programmierer will nun wissen, ob das Sound-Modul schon initialisiert wurde. Beziehungsweise noch verfügbar ist. |
Dann stelle ich mal die Frage: Warum weiß der Programmierer das nicht? Entweder er hat das Sound-Modul initialisiert oder eben nicht.  Aber wie auch immer: Ich will jetzt nicht rum diskutieren ob es in einer Bibliothek, wo ein Programmierer von Außen Objekt initialisieren und wieder frei geben kann, sinn macht oder nicht.
Lg, Martin
_________________ Ein Nutzer der Ecke
|
|
iKilledKenny
      
Beiträge: 394
Erhaltene Danke: 8
Win XP
D5 Prof, C# Express 2005
|
Verfasst: Do 21.08.08 16:00
|
|
Martin1966
      
Beiträge: 1068
Win 2000, Win XP
Delphi 7, Delphi 2005
|
Verfasst: Do 21.08.08 16:04
iKilledKenny hat folgendes geschrieben: | z.B. finde ich folgendes ein sehr elegantes Konstrukt. |
Du findest es also elegant ein Objekt freizugeben welches nicht initialisiert wurde - also Sourcecode umsonst auszuführen? Hm...  ich jedenfalls nicht.
Lg, Martin
_________________ Ein Nutzer der Ecke
|
|
iKilledKenny
      
Beiträge: 394
Erhaltene Danke: 8
Win XP
D5 Prof, C# Express 2005
|
Verfasst: Do 21.08.08 16:06
Initialisiert schon, aber eben mit nil. Analog verfahre ich auch mit Strings (''), Integern (0) etc.

|
|
Yogu
      
Beiträge: 2598
Erhaltene Danke: 156
Ubuntu 13.04, Win 7
C# (VS 2013)
|
Verfasst: Do 21.08.08 16:12
Den try ... finally-Block brauchst du nur um das Create zu spannen:
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13:
| var list: TList; begin list := nil; if (irgendwas > irgendwasAnderes) then Exit;
list := TList.Create; try finally list.Free; end; end; |
Allerdings kommt dann die Meldung, dass list zugewiesen wurde, der Wert aber nicht verwendet wurde. In diesem Fall kannst du die Initialisierung also weglassen. Aus diesem Grund initialisiert Delphi die Variablen nicht - dadurch werden Befehle und somit Zeit gespart. Du solltest Variablen nur dann initialisieren, wenn es auch notwendig ist.
|
|
iKilledKenny
      
Beiträge: 394
Erhaltene Danke: 8
Win XP
D5 Prof, C# Express 2005
|
Verfasst: Do 21.08.08 16:15
Das Beispiel war vielleicht ein bischen kurz und knapp. Wenn ich solch ein Konstrukt verwende, dann meistens in großen Routinen mit vielen Objekt-Variablen. Am Anfang initialisiere ich die alle mit nil und beim Verlassen ruf ich für alle ein free auf. Damit gehe ich sicher, dass ich jederzeit aus dieser Routine rauspringen kann und kein Speicherleck habe.
Das mit dem Rauspringen im Übrigen deshalb, weil es den Code wesentlich lesbarer macht. Man hat keine 14. Einrückung mehr in der 6 geschachtelten if-Abfrage und solch Zeug.
|
|
CoWa 
      
Beiträge: 17
Windows XP Embedded
|
Verfasst: Do 21.08.08 16:39
Hab das .destroy entfernt, Zugriffsfehler bleibt aber erhalten 
|
|
Boldar
      
Beiträge: 1555
Erhaltene Danke: 70
Win7 Enterprise 64bit, Win XP SP2
Turbo Delphi
|
Verfasst: Do 21.08.08 16:44
Dann müsstest du vielleicht mehr code rausrücken, meine Kristallkugel hat grad nen Sprung!
|
|
elundril
      
Beiträge: 3747
Erhaltene Danke: 123
Windows Vista, Ubuntu
Delphi 7 PE "Codename: Aurora", Eclipse Ganymede
|
Verfasst: Do 21.08.08 16:44
gibst du vielleicht etwas frei was noch gar nicht exisitiert??
Vielleicht wird die Procedure mit dem Create vorher gar nicht aufgerufen..
lg elundril
_________________ This Signature-Space is intentionally left blank.
Bei Beschwerden, bitte den Beschwerdebutton (gekennzeichnet mit PN) verwenden.
|
|