Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Programmieren allgemein (https://www.delphipraxis.net/40-programmieren-allgemein/)
-   -   Prüfung auf Assigned(MyObject) true obwohl MyObject nicht initialisiert wurde (https://www.delphipraxis.net/200768-pruefung-auf-assigned-myobject-true-obwohl-myobject-nicht-initialisiert-wurde.html)

freejay 23. Mai 2019 12:58


Prüfung auf Assigned(MyObject) true obwohl MyObject nicht initialisiert wurde
 
Hallo zusammen,

vielleicht stehe ich ja nur unglaublich auf dem Schlauch aber müsste in dem Codebeispiel "Assigned(slShow)" nicht false sein?

Delphi-Quellcode:
procedure TfMain.Button1Click(Sender: TObject);
var
  In_A: string;
  slShow: TStringList;
begin
  In_A := '';

  try
    if In_A = '' then
      exit;

    slShow := TStringList.Create;
  finally
    if Assigned(slShow) then
      slShow.Free;
  end;
end;
Wenn nein: Wie prüfe ich denn richtig, ob slShow freigeben kann/muss?

Aber - und mindestens genauso schlimm - die Zeile "if Assigned(slShow) then" wird ja nur ausgeführt, weil das "exit" zu einer Access Violation führt!

Ist vielleicht meine Installation kaputt?

Bin dankbar für jede Hilfe!

Gruß

Freejay

PS: Das ist ein Testprojekt mit zwei Buttons, einem Memofeld und einem Opendialog. Sonst nix. Frisch zusammengebastelt.

Uwe Raabe 23. Mai 2019 13:07

AW: Prüfung auf Assigned(MyObject) true obwohl MyObject nicht initialisiert
 
Zitat:

Zitat von freejay (Beitrag 1432938)
vielleicht stehe ich ja nur unglaublich auf dem Schlauch aber müsste in dem Codebeispiel "Assigned(slShow)" nicht false sein?

Eine (non-managed) lokale Variable ist nicht initialisiert. Das gilt auch für Object-Variablen; die kann auf alles mögliche zeigen.

Zitat:

Zitat von freejay (Beitrag 1432938)
Wenn nein: Wie prüfe ich denn richtig, ob slShow freigeben kann/muss?

Deswegen sollte slShow vor dem try auf nil gesetzt werden.

Zitat:

Zitat von freejay (Beitrag 1432938)
die Zeile "if Assigned(slShow) then" wird ja nur ausgeführt, weil das "exit" zu einer Access Violation führt!

Der finally-Abschnitt wird immer ausgeführt - auch bei einem Exit innerhalb eines try-finally.

Delphi.Narium 23. Mai 2019 13:10

AW: Prüfung auf Assigned(MyObject) true obwohl MyObject nicht initialisiert wurde
 
Die Prüfung wird vom Free doch selbst schon durchgeführt, das kannst Du Dir von daher eigentlich sparen.

Und alles hinter dem finally wird immer ausgeführt.

Uwe Raabe 23. Mai 2019 13:13

AW: Prüfung auf Assigned(MyObject) true obwohl MyObject nicht initialisiert wurde
 
Zitat:

Zitat von Delphi.Narium (Beitrag 1432940)
Die Prüfung wird vom Free doch selbst schon durchgeführt, das kannst Du Dir von daher eigentlich sparen.

Knallt aber hier trotzdem.

Zitat:

Zitat von Delphi.Narium (Beitrag 1432940)
Und alles hinter dem finally wird immer ausgeführt.

Genauer: Alles zwischen
Delphi-Quellcode:
finally
und dem zugehörigen
Delphi-Quellcode:
end
.

Schokohase 23. Mai 2019 13:16

AW: Prüfung auf Assigned(MyObject) true obwohl MyObject nicht initialisiert wurde
 
Fassen wir alles zusammen, dann ergibt sich
Delphi-Quellcode:
procedure TfMain.Button1Click(Sender: TObject);
var
  In_A: string;
  slShow: TStringList;
begin
  In_A := '';
  slShow := nil;

  try
    if In_A = '' then
      exit;

    slShow := TStringList.Create;
  finally
    slShow.Free;
  end;
end;

freejay 23. Mai 2019 13:18

AW: Prüfung auf Assigned(MyObject) true obwohl MyObject nicht initialisiert wurde
 
Hey, danke Euch beiden. :thumb:

Nach 20 Jahren Delphi ein paar Basics aufgefrischt...

Irgendwas fällt immer mal wieder hinten runter, wenn man's lange nicht braucht... :roll:

freejay 23. Mai 2019 13:18

AW: Prüfung auf Assigned(MyObject) true obwohl MyObject nicht initialisiert wurde
 
Zitat:

Zitat von Schokohase (Beitrag 1432943)
Fassen wir alles zusammen, dann ergibt sich
Delphi-Quellcode:
procedure TfMain.Button1Click(Sender: TObject);
var
  In_A: string;
  slShow: TStringList;
begin
  In_A := '';
  slShow := nil;

  try
    if In_A = '' then
      exit;

    slShow := TStringList.Create;
  finally
    slShow.Free;
  end;
end;

So sieht's jetzt bei mir auch aus! :-)

Delphi.Narium 23. Mai 2019 13:22

AW: Prüfung auf Assigned(MyObject) true obwohl MyObject nicht initialisiert wurde
 
Mein Delpbi gibt mir bei der Variante aus dem Eingangspost immer eine Compilerwarnung aus.

Beim slShow.Free sagt es, dass slShow eventuell nicht initialisiert sein könnte.

Eben weil alles zwischen finally und dem zugehörigen end ausgeführt wird, das Create wird aber nicht immer ausgeführt, da die Routine ja mit exit vorher verlassen wird.

Daher: Compilerwarnungen beachten, sie sind manchmal lässtig, aber immer hilfreich. ;-)

Bernhard Geyer 23. Mai 2019 13:23

AW: Prüfung auf Assigned(MyObject) true obwohl MyObject nicht initialisiert wurde
 
Zitat:

Zitat von freejay (Beitrag 1432945)
Zitat:

Zitat von Schokohase (Beitrag 1432943)
Fassen wir alles zusammen, dann ergibt sich
Delphi-Quellcode:
procedure TfMain.Button1Click(Sender: TObject);
var
  In_A: string;
  slShow: TStringList;
begin
  In_A := '';
  slShow := nil;

  try
    if In_A = '' then
      exit;

    slShow := TStringList.Create;
  finally
    slShow.Free;
  end;
end;

So sieht's jetzt bei mir auch aus! :-)

Sollte es hier nicht eine Compilerwarnung geben?
Die Zeile "slShow := TStringList.Create;" sollte vor dem try stehen.

haentschman 23. Mai 2019 13:25

AW: Prüfung auf Assigned(MyObject) true obwohl MyObject nicht initialisiert wurde
 
Hallöle...8-)

Besser...
Delphi-Quellcode:
procedure TfMain.Button1Click(Sender: TObject);
var
  In_A: string;
  slShow: TStringList;
begin
  In_A := '';

  slShow := TStringList.Create;
  try
    if In_A = '' then
      exit;
     
  finally
    slShow.Free;
  end;
end;
oder

Delphi-Quellcode:
procedure TfMain.Button1Click(Sender: TObject);
var
  In_A: string;
  slShow: TStringList;
begin
  In_A := '';

  if In_A = '' then
  begin
    exit;
  end
  else
  begin
    slShow := TStringList.Create;
    try
      // deins    
    finally
      slShow.Free;
    end;
  end;
end;
oder

Delphi-Quellcode:
procedure TfMain.Button1Click(Sender: TObject);
var
  In_A: string;
  slShow: TStringList;
begin
  In_A := '';

  if not (In_A = '') then
  begin
    slShow := TStringList.Create;
    try
      // deins    
    finally
      slShow.Free;
    end;
  end;
end;

freejay 23. Mai 2019 13:26

AW: Prüfung auf Assigned(MyObject) true obwohl MyObject nicht initialisiert wurde
 
Zitat:

Zitat von haentschman (Beitrag 1432949)
Hallöle...8-)

Besser...
Delphi-Quellcode:
procedure TfMain.Button1Click(Sender: TObject);
var
  In_A: string;
  slShow: TStringList;
begin
  In_A := '';

  slShow := TStringList.Create;
  try
    if In_A = '' then
      exit;
     
  finally
    slShow.Free;
  end;
end;

Danke! Da hast Du natürlich recht: So setze ich es jetzt auch in meinen echten Projekten um...

Uwe Raabe 23. Mai 2019 13:26

AW: Prüfung auf Assigned(MyObject) true obwohl MyObject nicht initialisiert wurde
 
Wobei die Initialisierung von In_A streng genommen redundant ist, da strings als managed type automatisch initialisiert wird. Der Lesbarkeit halber würde ich das aber schon so lassen.

Zitat:

Zitat von Bernhard Geyer (Beitrag 1432947)
Sollte es hier nicht eine Compilerwarnung geben?
Die Zeile "slShow := TStringList.Create;" sollte vor dem try stehen.

Nein, das ist durchaus ein gängiges Muster und erst recht vom Compiler nicht zu beanstanden.

Schokohase 23. Mai 2019 13:38

AW: Prüfung auf Assigned(MyObject) true obwohl MyObject nicht initialisiert wurde
 
Zitat:

Zitat von Uwe Raabe (Beitrag 1432951)
Zitat:

Zitat von Bernhard Geyer (Beitrag 1432947)
Sollte es hier nicht eine Compilerwarnung geben?
Die Zeile "slShow := TStringList.Create;" sollte vor dem try stehen.

Nein, das ist durchaus ein gängiges Muster und erst recht vom Compiler nicht zu beanstanden.

Beispiel:
Delphi-Quellcode:
procedure foo;
var
  sl1, sl2: TStringList;
begin
  sl1 := nil;
  sl2 := nil;
  try

    // beliebiger code hier

    sl1 := TStringList.Create;

    // beliebiger code hier

    sl2 := TStringList.Create;

    // beliebiger code hier

  finally
    sl1.Free;
    sl2.Free;
  end;
end;
Wenn an irgendeiner Stelle von "beliebiger code hier" eine Exception geworfen wird, oder mit Exit der Code verlassen werden soll, dann wird der finally-Block ohne Probleme abgearbeitet.

Dennis07 23. Mai 2019 23:18

AW: Prüfung auf Assigned(MyObject) true obwohl MyObject nicht initialisiert wurde
 
Das Problem wird nur sein, dass du dann nicht mehr den ursprünglichen Fehler mittels Exception-Handling abfangen kannst, weil du dann im
Delphi-Quellcode:
finally
-Abschnitt eine Access-Violation bekommst.
Auch geht das so nur bei objekten, die nicht voneinander abhängig sind.

Schokohase 23. Mai 2019 23:49

AW: Prüfung auf Assigned(MyObject) true obwohl MyObject nicht initialisiert wurde
 
Zitat:

Zitat von Dennis07 (Beitrag 1433001)
Das Problem wird nur sein, dass du dann nicht mehr den ursprünglichen Fehler mittels Exception-Handling abfangen kannst, weil du dann im
Delphi-Quellcode:
finally
-Abschnitt eine Access-Violation bekommst.

Probier es aus, so gibt es eben kein Problem und die Exceptions funktionieren wunderbar.

BTW: Du weißt, dass die Methode
Delphi-Quellcode:
Free
auf
Delphi-Quellcode:
nil
prüft bevor diese den Destructor aufruft? Also davon kann es keine AV geben.
Zitat:

Zitat von Dennis07 (Beitrag 1433001)
Auch geht das so nur bei objekten, die nicht voneinander abhängig sind.

Dann muss man eigentlich nur auf die Reihenfolge bei der Freigabe achten (oder darf gar nicht freigeben, wenn man das Lifetime-Management delegiert habe)

freimatz 24. Mai 2019 13:27

AW: Prüfung auf Assigned(MyObject) true obwohl MyObject nicht initialisiert wurde
 
Puh, da ist einiges falsch.

Das Create gehört vor den try.

Dass das obige "sl1.Free;" funktioniert, liegt vielleicht nur daran, dass bei TStringList zufällig nichts schlimmes passiert.
Free ruft Destroy() auf und wenn dort auf Felder zugegriffen wird, dann gibt es zwangsläufig eine Schutzverletzung.
Wenn bei obigem "// beliebiger code hier" eine Exception passiert, dann bleibt sl1 nil

"Dass die Methode Free auf nil prüft" ist auch falsch. FreeAndNil prüft dagegen.

Uwe Raabe 24. Mai 2019 14:39

AW: Prüfung auf Assigned(MyObject) true obwohl MyObject nicht initialisiert wurde
 
Zitat:

Zitat von freimatz (Beitrag 1433057)
"Dass die Methode Free auf nil prüft" ist auch falsch. FreeAndNil prüft dagegen.

Du irrst gewaltig! In beiden Fällen!

Delphi-Quellcode:
procedure TObject.Free;
begin
// under ARC, this method isn't actually called since the compiler translates
// the call to be a mere nil assignment to the instance variable, which then calls _InstClear
{$IFNDEF AUTOREFCOUNT}
  if Self <> nil then
    Destroy;
{$ENDIF}
end;
Delphi-Quellcode:
procedure FreeAndNil(var Obj);
{$IF not Defined(AUTOREFCOUNT)}
var
  Temp: TObject;
begin
  Temp := TObject(Obj);
  Pointer(Obj) := nil;
  Temp.Free;
end;
{$ELSE}
begin
  TObject(Obj) := nil;
end;
{$ENDIF}

Schokohase 24. Mai 2019 14:45

AW: Prüfung auf Assigned(MyObject) true obwohl MyObject nicht initialisiert wurde
 
Zitat:

Zitat von freimatz (Beitrag 1433057)
Puh, da ist einiges falsch.

Das Create gehört vor den try.

Dass das obige "sl1.Free;" funktioniert, liegt vielleicht nur daran, dass bei TStringList zufällig nichts schlimmes passiert.
Free ruft Destroy() auf und wenn dort auf Felder zugegriffen wird, dann gibt es zwangsläufig eine Schutzverletzung.
Wenn bei obigem "// beliebiger code hier" eine Exception passiert, dann bleibt sl1 nil

"Dass die Methode Free auf nil prüft" ist auch falsch. FreeAndNil prüft dagegen.

Bitte, erst informieren, dann dementieren.

Das Create kann stehen wo will.
Delphi-Quellcode:
var
  f: TObject;
begin
  f := TObject.Create;
  try

  finally
    f.Free;
  end;
end;
oder
Delphi-Quellcode:
var
  f: TObject;
begin
  f := nil;
  try
    f := TObject.Create;

  finally
    f.Free;
  end;
end;
Ist beides gleichwertig. Die zweite Variante macht allerdings nur dann richtig Sinn, wenn man mehrere Instanzen mit einem Resourcen-Schutzblock absichern kann/will.

Das mit dem Free und nil hat Uwe ja schon erklärt.

Manchmal ist Erkenntnis nur einen Klick entfernt und da wundert man sich halt schon manchmal über das was hier an Wissen offenbart wird.

freimatz 25. Mai 2019 12:40

AW: Prüfung auf Assigned(MyObject) true obwohl MyObject nicht initialisiert wurde
 
Dazu gibt es ja zum Glück das Forum.
Asche auf mein Haupt. Tut mir leid. :oops:
Ich war mir so sicher ... War das schon immer so?

Lustig: Habe nach "procedure TObject.Free;" bei mir gesucht und gefunden:
Delphi-Quellcode:
procedure TObject.Free;
begin
  Dispose(PObject(@Self), Done);
end;
Allerdings stand oben drin "Turbo Pascal Version 7.0" :wink:

dummzeuch 25. Mai 2019 16:28

AW: Prüfung auf Assigned(MyObject) true obwohl MyObject nicht initialisiert wurde
 
Zitat:

Zitat von freejay (Beitrag 1432950)
Zitat:

Zitat von haentschman (Beitrag 1432949)

Besser...
Delphi-Quellcode:
procedure TfMain.Button1Click(Sender: TObject);
var
  In_A: string;
  slShow: TStringList;
begin
  In_A := '';

  slShow := TStringList.Create;
  try
    if In_A = '' then
      exit;
     
  finally
    slShow.Free;
  end;
end;

Danke! Da hast Du natürlich recht: So setze ich es jetzt auch in meinen echten Projekten um...

Naja, das ist zwar nicht falsch, erzeugt aber, wenn In_A = '', unnötigerweise die Stringlist, nur um sie dann sofort wieder freizugeben. Bei einer Stringlist ist das noch relativ egal, aber bei komplexeren Klassen kann der Constructor schonmal einiges an Ressource fressen, so dass man sie nur erzeugen sollte, wenn wirklich notwendig. Die Variante mit slShow := nil vor dem Try ist in dem Fall dann besser.


Alle Zeitangaben in WEZ +1. Es ist jetzt 23:47 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