Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi Warum geht FreeAndNil nicht? (https://www.delphipraxis.net/197425-warum-geht-freeandnil-nicht.html)

ford42 6. Aug 2018 09:34

Delphi-Version: 10.2 Tokyo

Warum geht FreeAndNil nicht?
 
Hey,

wenn ich FreeAndNil in der Delete-Methode verwende bekomme ich einen Zugriffsfehler.

https://pastebin.com/9Rj84HKn

Weiß jemand wieso?


Vielen Dank
LG ford

[Edit: mkinzler]
Delphi-Quellcode:
unit UnitVerkettetListe;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;

type
  PNode = ^TNode;
  TNode = record
    data: String;
    previous: PNode;
    next: PNode;
  end;
  TForm1 = class(TForm)
    Lbl_Show: TLabel;
    Bt_Back: TButton;
    Bt_Insert: TButton;
    Bt_Vorward: TButton;
    Ed_Insert: TEdit;
    Bt_Delete: TButton;
    procedure Bt_InsertClick(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure RefreshButtons;
    procedure Bt_BackClick(Sender: TObject);
    procedure Bt_VorwardClick(Sender: TObject);
    procedure RefreshLbl;
    procedure Bt_DeleteClick(Sender: TObject);
    procedure Refresh;
  private
    { Private-Deklarationen }
    PCurrentNode: PNode;
    PFirstNode: PNode;
    PLastNode: PNode;
  public
    { Public-Deklarationen }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.Bt_BackClick(Sender: TObject);
begin
  PCurrentNode := PCurrentNode.previous;
  Refresh;
end;

procedure TForm1.Bt_DeleteClick(Sender: TObject);
var
  PBufferNode: PNode;
begin
  if PCurrentNode.previous <> nil then
  begin
    PCurrentNode := PCurrentNode.previous;
    PBufferNode := PCurrentNode.next;
    if PCurrentNode.next.next <> nil then
    begin
      PCurrentNode.next := PCurrentNode.next.next;
    end
    else
    begin
      PCurrentNode.next := nil;
    end;
    if PBufferNode.next <> nil then
    begin
      PBufferNode.next.previous := PBufferNode.previous;
    end;
    PBufferNode := nil;
    Refresh;
    //PBufferNode.previous := nil;
    //PBufferNode.next := nil;
    //FreeAndNil(PBufferNode);
  end
  else if PCurrentNode.next <> nil then
  begin
    PCurrentNode := PCurrentNode.next;
    PBufferNode := PCurrentNode.previous;
    if PCurrentNode.previous.previous <> nil then
    begin
      PCurrentNode.previous := PCurrentNode.previous.previous;
    end
    else
    begin
      PCurrentNode.previous := nil;
    end;
  PBufferNode := nil;
  Refresh;
  end
  else
  begin
    PCurrentNode := nil;
    Bt_Back.Enabled := False;
    Bt_Vorward.Enabled := False;
    RefreshLbl;
  end;
end;

procedure TForm1.Bt_InsertClick(Sender: TObject);
begin
  New(PCurrentNode);
  PCurrentNode.data := Ed_Insert.Text;
  Ed_Insert.Text := '';
  PCurrentNode.previous := nil;
  PCurrentNode.next := nil;

  if PFirstNode = nil then
  begin
    PFirstNode := PCurrentNode;
  end
  else
  begin
    PLastNode.next := PCurrentNode;
    PCurrentNode.previous := PLastNode;
  end;
  PLastNode := PCurrentNode;
  Refresh;

end;

procedure TForm1.Bt_VorwardClick(Sender: TObject);
begin
 PCurrentNode := PCurrentNode.next;
 Refresh;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
 Bt_Back.Enabled := False;
 Bt_Vorward.Enabled := False;
 PFirstNode := nil;
 PLastNode := nil;
end;

procedure TForm1.RefreshButtons;
begin
  if PCurrentNode.previous <> nil then
  begin
    Bt_Back.Enabled := True;
  end
  else
  begin
    Bt_Back.Enabled := False;
  end;

  if PCurrentNode.next <> nil then
  begin
    Bt_Vorward.Enabled := True;
  end
  else
  begin
    Bt_Vorward.Enabled := False;
  end;

end;

procedure TForm1.RefreshLbl;
begin
  if PCurrentNode <> nil then
  begin
    Lbl_Show.Caption := PCurrentNode.data;
  end
  else
  begin
    Lbl_Show.Caption := '';
  end;
end;

procedure TForm1.Refresh;
begin
  RefreshButtons;
  RefreshLbl;
end;


end.
[/edit]

Fritzew 6. Aug 2018 09:43

AW: Warum geht FreeAndNil nicht?
 
Was macht freeandnil?

Es geht davon aus das der Pointer ein Object ist.....
Du hast aber einen record.....

Delphi-Quellcode:
procedure FreeAndNil(var Obj);

var
  Temp: TObject;
begin
  Temp := TObject(Obj);
  Pointer(Obj) := nil;
  Temp.Free; // Hier knallt es bei Dir
end;
Und bitte die Source hier mit rein in Delphi Tags

mkinzler 6. Aug 2018 09:43

AW: Warum geht FreeAndNil nicht?
 
Eine genauere Beschreibung Deines Problems und die Angabe der geanen Zeile wäre vielleicht auch hilfreich.

p80286 6. Aug 2018 09:48

AW: Warum geht FreeAndNil nicht?
 
Gegenfrage:
wie sieht Dein Sourcecode aus?

Gruß
K-H

@markus
jetzt sieht jeder diese begin/end Orgie.
Da gibt es bessere Beispiele für doppelt verkettete Listen.

ford42 6. Aug 2018 09:50

AW: Warum geht FreeAndNil nicht?
 
Danke!

Also muss ich es gar nicht freigeben?

Ghostwalker 6. Aug 2018 09:50

AW: Warum geht FreeAndNil nicht?
 
Zitat:

Zitat von Fritzew (Beitrag 1409895)
Was macht freeandnil?

Es geht davon aus das der Pointer ein Object ist.....
Du hast aber einen record.....

Delphi-Quellcode:
procedure FreeAndNil(var Obj);

var
  Temp: TObject;
begin
  Temp := TObject(Obj);
  Pointer(Obj) := nil;
  Temp.Free; // Hier knallt es bei Dir
end;
Und bitte die Source hier mit rein in Delphi Tags

Jap. Außerdem wird vorher dem Zeiger Nil zugewiesen.


Freigeben musst du sehr wohl, entweder via Dispose oder FreeMem.
Passend zum Thema hier ein Tutorial

ford42 6. Aug 2018 09:53

AW: Warum geht FreeAndNil nicht?
 
Mein Sourcecode ist doch oben?

EDIT: Die Methode sah eig vorher so aus:

Delphi-Quellcode:
procedure TForm1.Bt_DeleteClick(Sender: TObject);
var
  PBufferNode: PNode;
begin
  if PCurrentNode.previous <> nil then
  begin
    PCurrentNode := PCurrentNode.previous;
    PBufferNode := PCurrentNode.next;
    if PCurrentNode.next.next <> nil then
    begin
      PCurrentNode.next := PCurrentNode.next.next;
    end
    else
    begin
      PCurrentNode.next := nil;
    end;
    if PBufferNode.next <> nil then
    begin
      PBufferNode.next.previous := PBufferNode.previous;
    end;
    //PBufferNode := nil;
    Refresh;
    //PBufferNode.previous := nil;
    //PBufferNode.next := nil;
    FreeAndNil(PBufferNode);
  end
  else if PCurrentNode.next <> nil then
  begin
    PCurrentNode := PCurrentNode.next;
    PBufferNode := PCurrentNode.previous;
    if PCurrentNode.previous.previous <> nil then
    begin
      PCurrentNode.previous := PCurrentNode.previous.previous;
    end
    else
    begin
      PCurrentNode.previous := nil;
    end;
  FreeAndNil(PBufferNode);
  Refresh;
  end
  else
  begin
    FreeAndNil(PCurrentNode);
    //PCurrentNode := nil;
    Bt_Back.Enabled := False;
    Bt_Vorward.Enabled := False;
    RefreshLbl;
  end;
end;

Klaus01 6. Aug 2018 10:06

AW: Warum geht FreeAndNil nicht?
 
Delphi-Quellcode:
   PBufferNode := nil;
    Refresh;
    //PBufferNode.previous := nil;
    //PBufferNode.next := nil;
    //FreeAndNil(PBufferNode);
bleibt dasPBufferNode := nil stehen wenn Du freeAndNil einfügst?

Grüße
Klaus

Ghostwalker 6. Aug 2018 10:20

AW: Warum geht FreeAndNil nicht?
 
Wie Fritz schon sagte, arbeitet FreeAndNil mit Objekt-Instanzen, nicht mit typisierten Zeigern.

Da es sich um einen typisierten Zeiger handelt kannst du das ganze mit Dispose freigeben.

Fritzew 6. Aug 2018 10:23

AW: Warum geht FreeAndNil nicht?
 
Ok um das zu vervollständigen:
Delphi-Quellcode:
// Anstatt
// FreeAndNil(PBufferNode);
// so:
 dispose(PBufferNode); // Freigeben des Nodes
 PBufferNode := nil;
 Refresh;


Alle Zeitangaben in WEZ +1. Es ist jetzt 03:14 Uhr.

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