Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   GUI-Design mit VCL / FireMonkey / Common Controls (https://www.delphipraxis.net/18-gui-design-mit-vcl-firemonkey-common-controls/)
-   -   Delphi Form close - EINvalidPointer (https://www.delphipraxis.net/200328-form-close-einvalidpointer.html)

Int3g3r 10. Apr 2019 08:14

Form close - EINvalidPointer
 
Liste der Anhänge anzeigen (Anzahl: 1)
Guten Tag,

Ich verwende das erste mal eine TObjectList. Leider bekomme ich nun beim close; des Forms eine exception: EInvalidPointer 'Ungültige zeigeroperation'.

Delphi-Quellcode:
// unit System;
procedure TObject.FreeInstance;
begin
  CleanupInstance;
  _FreeMem(Pointer(Self)); // <- Hier wird die exception ausgelöst.
end;
Im Anhang befindet sich der Source.
close; <- Zeile 292

Programmbeschreibung:

Anhand einer Mitarbeiter Tabelle erstelle ich Frames. Für jeden Mitarbeiter erzeuge ich ein Frame, dies füge ich einer TObjectList(PersonList) hinzu. Der Owner bei der TObjectList ist auf true.

In der Mitarbeiter Tabelle habe ich Aktive und nicht Aktive Mitarbeiter. Wenn alle Mitarbeiter auf Aktiv sind kommt kein Pointer-Fehler. Sobald ich aber ein Mitarbeiter deaktiviere kommt beim close der Pointer-Fehler. Ob ich das Free am ende mache oder nicht hat keinen einfluss auf die Exception

Ich habe nun mehrmals die TObjectList mit Breaktpoints beobachtet. Ich habe die korrekte Anzahl an Objekten in dieser Liste. Daher verstehe ich nicht warum ich ein Pointerfehler bekomme.

Mfg Int3g3r

hoika 10. Apr 2019 08:20

AW: Form close - EINvalidPointer
 
Hallo,
setz erst mal das Owner auf False.

Wenn du ein Frame erzeugst, wem gehört der Frame, dem erzeugenden Form?
Wenn ja, wir ja der Frame versucht, 2mal freizugegeben, einmal in der ObjectList und dann im Form selber.

Ich würde das Form als Owner des Frames setzen und der ObjectList, wie oben geschrieben, den owner wegnehmen (False).

Int3g3r 10. Apr 2019 08:29

AW: Form close - EINvalidPointer
 
Zitat:

Zitat von hoika (Beitrag 1429952)
Hallo,
setz erst mal das Owner auf False.

Wenn du ein Frame erzeugst, wem gehört der Frame, dem erzeugenden Form?
Wenn ja, wir ja der Frame versucht, 2mal freizugegeben, einmal in der ObjectList und dann im Form selber.

Ich würde das Form als Owner des Frames setzen und der ObjectList, wie oben geschrieben, den owner wegnehmen (False).

Hmm... Also das Ziel bei einer TObjectList ist doch das die Items automatisch freigegeben werden wenn der owner auf true ist. Somit muss ich nicht jedes Objekt manuell in einer Schleife freigeben.

Ich habe es trotzdem mal versucht und den owner auf false gesetzt. Dies hat an der situation nichts geändert.

Klaus01 10. Apr 2019 08:32

AW: Form close - EINvalidPointer
 
.. was passiert denn, wenn eine Mitarbeiter deaktiviert wird?
Entfernst Du dann das Frame aus der Liste - oder beendest Du das Frame nur?

Grüße
Klaus

Int3g3r 10. Apr 2019 08:36

AW: Form close - EINvalidPointer
 
Zitat:

Zitat von Klaus01 (Beitrag 1429954)
.. was passiert denn, wenn eine Mitarbeiter deaktiviert wird?
Entfernst Du dann das Frame aus der Liste - oder beendest Du das Frame nur?

Grüße
Klaus

Nein, ich werde die komplette TObjecList freigeben und neu aufbauen, somit auch alle Frames freigeben/neu erzeugen. Wenn ein Mitarbeiter deaktiviert wurde wird dieser bei der SQL abfrage nun nicht mehr in der Tabelle angezeigt. Anhand der anzahl der Tabelleneinträge werden mir die anzahl Frames erzeugt.

Code:
   qryMitarbeiter.Close;
   qryMitarbeiter.SQL.Text := 'select * from mitarbeiter where mitarbeiter.aktiv = 1';
   qryMitarbeiter.Open;

hoika 10. Apr 2019 09:16

AW: Form close - EINvalidPointer
 
Hallo,
Zitat:

ich werde die komplette TObjecList freigeben
werde = Zukunft
oder machst du das bereits?

haentschman 10. Apr 2019 09:37

AW: Form close - EINvalidPointer
 
Moin...8-)
Zitat:

Also das Ziel bei einer TObjectList ist doch das die Items automatisch freigegeben werden wenn der owner auf true ist.
Diese Aussage ist falsch. :warn:
Zum Verständnis...Entweder die Objektliste oder der Owner gibt den Frame frei. :warn:
Delphi-Quellcode:
// 1. Variante
FrmPerson := TFrmPerson.Create(nil); // Owner hier auf nil
PersonList := TObjectList<TfrmPerson>.Create(True); // bleibt

// 2. Variante
FrmPerson := TFrmPerson.Create(self); // Owner bleibt
PersonList := TObjectList<TfrmPerson>.Create(False); // heißt, daß die Liste ihre Objekte nicht selbst freigibt
Delphi-Quellcode:
PersonList := TObjectList<TfrmPerson>.Create(True);
PersonList.Free;
Erzeugen und freigeben der Liste bitte im FormCreate/FormDestroy. Da sind sie besser aufgehoben. :wink:

eine Bitte:
Keine globalen Variablen. :warn:
Delphi-Quellcode:
var
  PersonList : TObjectList<TfrmPerson>;
besser:
Delphi-Quellcode:
TfrmAnsicht = class(TForm)
private
 FPersonList : TObjectList<TfrmPerson>;

peterbelow 10. Apr 2019 09:55

AW: Form close - EINvalidPointer
 
Zitat:

Zitat von Int3g3r (Beitrag 1429951)
Guten Tag,

Ich verwende das erste mal eine TObjectList. Leider bekomme ich nun beim close; des Forms eine exception: EInvalidPointer 'Ungültige zeigeroperation'.


Programmbeschreibung:

Anhand einer Mitarbeiter Tabelle erstelle ich Frames. Für jeden Mitarbeiter erzeuge ich ein Frame, dies füge ich einer TObjectList(PersonList) hinzu. Der Owner bei der TObjectList ist auf true.

Wenn man TComponent-Abkömmlinge in einer TObjectlist mit OwnsObjects = true ablegt muss man sich sehr genau überlegen, wie denn nun die Verwaltung der Lebensdauer sein soll. TComponents haben normalerweise einen Owner, der automatisch alle Komponenten zerstört, wenn er selbst zerstört wird. Bei TControls ist das noch verschärft, da die auch noch einen Parent haben müssen, damit sie angezeigt werden. Der Parent ist ein Psychopath per excellance: er ermordet alle seine Kinder bevor er selbst ins Jenseits entschwindet :wink:. Es gibt da also reichlich Potential für Konflikte, zumal die Objectlist ja nicht mitbekommt, wenn ein in ihr enthaltenes Objekt anderswo zerstört wird. Sie enthält dann ungültige Objektreferenzen, die solche pointer-Fehler erzeugen, wenn die TObjectlist versucht, ihren Inhalt zu free-en.

In deinem Fall mußt Du also unbedingt die TObjectlist löschen und darfst dann auch keinen Fall mehr versuchen, eines der Frames "anzufassen", die existieren dann nämlich nicht mehr. Kode in TComponent sorgt dafür, dass der Owner benachrichtigt wird, wenn sein Eigentum externem Vandalismus anheim fällt, da gibt es also keine Probleme, und auch die Parent <-> Child Beziehung wird ordentlich beendet. Deine TObjectlist ist aber außerhalb der automatischen Verwaltung der Lebensdauer, da bist Du also selbst dafür verantwortlich, eine enthaltene Objektreferenz zu entfernen, wenn Du das Objekt anderswo zerstörst. TObjectlist hat eine Extract-Methode dafür, die entfernt eine Referenz aus der Liste ohne zu versuchen, die freizugeben.

Int3g3r 10. Apr 2019 10:05

AW: Form close - EINvalidPointer
 
Zitat:

Zum Verständnis...Entweder die Objektliste oder der Owner gibt den Frame frei.
Besten Dank für die Erklärung. Dies habe ich wohl falsch verstanden. Ich habe gedacht das der owner dann auf die TObjectList übertragen wird. Somit hatte ich 2 Owner.

Code:
// 1. Variante
FrmPerson := TFrmPerson.Create(nil); // Owner hier auf nil
PersonList := TObjectList<TfrmPerson>.Create(True); // bleibt
Habe ich nun wie in deinem beispiel getestet. Hat leider nichts gebracht der PointerFehler besteht weiterhin.

Im Frame habe ich noch Arrays[0..30] of Shortint; diese müssen ja nicht spezifisch freigegeben werden, richtig ?

Code:
TfrmAnsicht = class(TForm)
private
 FPersonList : TObjectList<TfrmPerson>;
Hmm... Ich möchte sehen welche Units ich Manuell eingebunden Habe.
Wenn ich dies wie in deinem Beispiel mache bin ich gezwungen die frame_Person in der ersten Uses einzutragen wo alle system units eingebunden werden.

Wenn ich diese global deklariere kann ich dies nach der Implementation machen und sehe somit auf anhib welche units ich eingebunden habe. Oder gibt es eine möglichkeit diese als private zu deklarieren nach der Implementation ?

Ah ja bevor ichs vergesse, Vielen Dank für die Hilfe! :-D

Int3g3r 10. Apr 2019 10:27

AW: Form close - EINvalidPointer
 
Zitat:

Zitat von peterbelow (Beitrag 1429968)
In deinem Fall mußt Du also unbedingt die TObjectlist löschen und darfst dann auch keinen Fall mehr versuchen, eines der Frames "anzufassen", die existieren dann nämlich nicht mehr. Kode in TComponent sorgt dafür, dass der Owner benachrichtigt wird, wenn sein Eigentum externem Vandalismus anheim fällt, da gibt es also keine Probleme, und auch die Parent <-> Child Beziehung wird ordentlich beendet. Deine TObjectlist ist aber außerhalb der automatischen Verwaltung der Lebensdauer, da bist Du also selbst dafür verantwortlich, eine enthaltene Objektreferenz zu entfernen, wenn Du das Objekt anderswo zerstörst. TObjectlist hat eine Extract-Methode dafür, die entfernt eine Referenz aus der Liste ohne zu versuchen, die freizugeben.

Hmm ich verstehe nicht wo meine Frames zerstört werden ? Ich habe keinen code der die Frames freigibt oder zerstört, ausser beim btnSchliessen. Oder werden bei PersonList.Free nur die Frames freigegeben aber die Referenzen in der Liste nicht gelöscht?

haentschman 10. Apr 2019 10:29

AW: Form close - EINvalidPointer
 
Zitat:

In deinem Fall mußt Du also unbedingt die TObjectlist löschen
...wieso? Ich verwalte einige der Forms in Objektlisten. (Owner = nil) Wenn man sich an die Regeln hällt, ist es kein Problem. Wichtig, die Liste im FormCreate/FormDestroy anlegen und zerstören.

Int3g3r 10. Apr 2019 13:29

AW: Form close - EINvalidPointer
 
Endlich !! 8-)

Habs herausgefunden!

Delphi-Quellcode:
   SetLength(MitarbeiterNamen, anzAktiveMitarbeiter-1);
   qryMitarbeiter.First;
   while not qryMitarbeiter.Eof do
      begin
         MitarbeiterNamen[i] := (qryMitarbeiterNAME.AsString + ' ' + qryMitarbeiterVORNAME.AsString);
         inc(i);
         qryMitarbeiter.Next;
      end;
Delphi-Quellcode:
 // KORREKT
SetLength(MitarbeiterNamen, anzAktiveMitarbeiter)
Kann mir jemand erklären warum ich hier keine exception bekommen habe ?
Er versucht einen String in den MitarbeiterNamen[i] einzutragen. Das Array war zu klein mit dem -1. Da hätte er doch motzen müssen wenn das Array zu klein ist und somit nicht über den index zugreifen kann.

Mfg Int3g3r

Neutral General 10. Apr 2019 13:34

AW: Form close - EINvalidPointer
 
Zitat:

Zitat von Int3g3r (Beitrag 1429984)
Kann mir jemand erklären warum ich hier keine exception bekommen habe ?
Er versucht einen String in den MitarbeiterNamen[i] einzutragen. Das Array war zu klein mit dem -1. Da hätte er doch motzen müssen wenn das Array zu klein ist und somit nichts in den index eintragen kann.

Weil Speicher Speicher ist. Und solange der Speicher von Mitarbeiter[i] verfügbar und schreibbar ist, ist alles "okay".
Okay in der Hinsicht, dass man Daten darein schreiben kann. Das Problem ist nur, dass du damit wahrscheinlich Speicher eines andere Objekts o.ä. überschreibst weswegen die Chance besteht, dass du später ggf. "unerklärbare" Überraschungs-Exceptions bekommst an Stellen die eigentlich komplett unproblematisch sind, weil du dir vorher den Speicher zerschossen hast.

haentschman 10. Apr 2019 13:44

AW: Form close - EINvalidPointer
 
Moin...:P
Dann würde ich anstelle des Arrays eine
Delphi-Quellcode:
MitarbeiterList : TObjectList<TMitarbeiter>;
und die Klasse dazu empfehlen. Da hast du die Größe des Arrays aus dem Kreuz.
Und solche Konstruckte sind mit der Klasse erledigt: qryMitarbeiterNAME.AsString + ' ' + qryMitarbeiterVORNAME.AsString :zwinker:
[Meine Meinung]
Arrays sind aus der Zeit wo es noch keine generischen Listen gab. :stupid::P

Int3g3r 10. Apr 2019 13:54

AW: Form close - EINvalidPointer
 
Vielen dank für eure Hilfe!

@haentschman:

Könntest du bitte mein "Post - 11:05" Uhr auf der ersten Seite lesen ?
Hätte gerne eine Antwort darauf ob man nach der implementation private variablen deklarieren kann ? Wenn ja wie ?

peterbelow 10. Apr 2019 13:56

AW: Form close - EINvalidPointer
 
Zitat:

Zitat von Int3g3r (Beitrag 1429984)
Endlich !! 8-)

Habs herausgefunden!

Delphi-Quellcode:
   SetLength(MitarbeiterNamen, anzAktiveMitarbeiter-1);
   qryMitarbeiter.First;
   while not qryMitarbeiter.Eof do
      begin
         MitarbeiterNamen[i] := (qryMitarbeiterNAME.AsString + ' ' + qryMitarbeiterVORNAME.AsString);
         inc(i);
         qryMitarbeiter.Next;
      end;
Delphi-Quellcode:
 // KORREKT
SetLength(MitarbeiterNamen, anzAktiveMitarbeiter)
Kann mir jemand erklären warum ich hier keine exception bekommen habe ?
Er versucht einen String in den MitarbeiterNamen[i] einzutragen. Das Array war zu klein mit dem -1. Da hätte er doch motzen müssen wenn das Array zu klein ist und somit nicht über den index zugreifen kann.

Mfg Int3g3r

Hast Du range-checking aktiviert, zumindest für den Debug-Build?

Int3g3r 10. Apr 2019 13:57

AW: Form close - EINvalidPointer
 
Zitat:

Zitat von peterbelow (Beitrag 1429989)
Hast Du range-checking aktiviert, zumindest für den Debug-Build?

Anscheinend nicht, wie lässt sich das aktivieren ?

Hab was gefunden :
Code:
{$R+} or {$R-} {$RANGECHECKS ON} or {$RANGECHECKS OFF}

peterbelow 10. Apr 2019 14:02

AW: Form close - EINvalidPointer
 
Liste der Anhänge anzeigen (Anzahl: 1)
Zitat:

Zitat von Int3g3r (Beitrag 1429990)
Zitat:

Zitat von peterbelow (Beitrag 1429989)
Hast Du range-checking aktiviert, zumindest für den Debug-Build?

Anscheinend nicht, wie lässt sich das aktivieren ?

Ist Teil der Konfiguration des Projektes, siehe nachfolgenden Screenshot.

Int3g3r 10. Apr 2019 14:06

AW: Form close - EINvalidPointer
 
Zitat:

Zitat von peterbelow (Beitrag 1429991)
Zitat:

Zitat von Int3g3r (Beitrag 1429990)
Zitat:

Zitat von peterbelow (Beitrag 1429989)
Hast Du range-checking aktiviert, zumindest für den Debug-Build?

Anscheinend nicht, wie lässt sich das aktivieren ?

Ist Teil der Konfiguration des Projektes, siehe nachfolgenden Screenshot.

Oh, sehr schön danke !

Klaus01 10. Apr 2019 14:18

AW: Form close - EINvalidPointer
 
Zitat:

Zitat von Int3g3r (Beitrag 1429988)
Vielen dank für eure Hilfe!

@haentschman:

Könntest du bitte mein "Post - 11:05" Uhr auf der ersten Seite lesen ?
Hätte gerne eine Antwort darauf ob man nach der implementation private variablen deklarieren kann ? Wenn ja wie ?

.. eine Klasse kann man nicht über interface und implemetation verteilen/aufteilen.

Grüße
Klaus

haentschman 10. Apr 2019 14:41

AW: Form close - EINvalidPointer
 
Delphi-Quellcode:
uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.ExtCtrls, Vcl.StdCtrls, Vcl.Buttons, Generics.Collections, Math, System.DateUtils,
  Data.DB, MemDS, DBAccess, IBC, Vcl.Grids, Vcl.DBGrids,
  // eigene uses
  dmod_prg, frame_Titel, frame_Person;
Wie siehts damit aus...dann kannst du deine Klassen vernünftig bestücken. 8-) Persönlich mag ich keine Units in den implementation uses wegen den Kreuzreferenzen. :wink:


Alle Zeitangaben in WEZ +1. Es ist jetzt 08:58 Uhr.

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