Delphi-PRAXiS
Seite 1 von 2  1 2      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Pointer auf Instanz zurückgeben (https://www.delphipraxis.net/210537-pointer-auf-instanz-zurueckgeben.html)

idontknow 8. Mai 2022 16:46

Delphi-Version: 5

Pointer auf Instanz zurückgeben
 
Moin.

Ich stell mich gerade zu blöd an, finde aber den Fehler nicht:

Ich versuche gerade, mir von einer Prozedur einen Zeiger auf ein in der Prozedur erzeugtes Objekt zurückgeben zu lassen.

Offenbar zeigt der Zeiger unmittelbar nach Rückkehr auf das Objekt mit dem richtigen Inhalt (1234).

Sobald dann ein neues Objekt (egal was) erzeugt wird, wird offenbar mein in der Prozedur erzeugtes Objekt überschrieben.

Die Freigabe des Objekts endet sogar in einer Schutzverletzung, offenbar wurde das Ding schon freigegeben. Aber durch wen und wieso?

Hat jemand eine Idee?

PS: Als erste Zeile steht "Delphi-Version: 5". Hab ich nicht geschrieben, steht auch nicht in meinem Profil, glaube ich... Keine Ahnung wie das dahin kommt.

Delphi-Quellcode:
unit Unit1;

interface

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

type
  TMyClass = class
  public
    Wert: integer;
  end;
  PMyClass = ^TMyClass;

  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private-Deklarationen }
  public
    { Public-Deklarationen }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}
procedure Test(var Zeiger: PMyClass);
var
  MyObject: TMyClass;
begin
  MyObject := TMyClass.Create;
  MyObject.Wert := 1234;
  Zeiger := @MyObject;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  pObjekt: PMyClass;
  AnderesObjekt: TMyClass;
begin
  Test(pObjekt);
  Caption := pObjekt^.Wert.ToString; // OK, 1234

  AnderesObjekt := TMyClass.Create;
  AnderesObjekt.Wert := 9876;

  Caption := pObjekt^.Wert.ToString; // Nun nicht mehr 1234...

  AnderesObjekt.Free;

  pObjekt^.Free; // AV
end;

end.

Bernhard Geyer 8. Mai 2022 17:12

AW: Pointer auf Instanz zurückgeben
 
MyObject: TMyClass ist schon die Referenz auf die Instanz.
Wieso noch eine Zeiger auf den Zeiger nutzen?

idontknow 8. Mai 2022 17:57

AW: Pointer auf Instanz zurückgeben
 
Weil ich in einer Anwendung eine Methode ersetzen will, die bereits existent ist und an vielen Stellen verwendet wird. Das Ding selbst ist in Assembler geschrieben und gibt mir einen Pointer auf ein Objekt zurück.

Das muss doch auch in Pascal irgendwie gehen? Und wieso verschwindet das Objekt, obwohl niemand es freigibt?

Fritzew 8. Mai 2022 18:09

AW: Pointer auf Instanz zurückgeben
 
Zitat:

Zitat von idontknow (Beitrag 1505584)
Weil ich in einer Anwendung eine Methode ersetzen will, die bereits existent ist und an vielen Stellen verwendet wird. Das Ding selbst ist in Assembler geschrieben und gibt mir einen Pointer auf ein Objekt zurück.

Das muss doch auch in Pascal irgendwie gehen? Und wieso verschwindet das Objekt, obwohl niemand es freigibt?

Weil in der procedure die Adresse der lokalen Variablen zurückgegeben wird

Delphi-Quellcode:
procedure Test(var Zeiger: PMyClass);
var
  MyObject: TMyClass;
begin
  MyObject := TMyClass.Create;
  MyObject.Wert := 1234;
  Zeiger := @MyObject; // Das zeigt jetzt auf die lokale Variable auf dem Stack
end;
Das kann so nicht funktionieren

idontknow 8. Mai 2022 18:44

AW: Pointer auf Instanz zurückgeben
 
Naja, das ist doch ein Objekt und keine einfache lokale Integer-Variable oder so...
Und ein Objekt, das nicht freigegeben wird, sollte doch für immer und ewig im Speicher liegen?
Ich dachte immer, bei Delphi wird nichts automatisch aufgeräumt?

Fritzew 8. Mai 2022 19:24

AW: Pointer auf Instanz zurückgeben
 
mit der Zuweisung
Delphi-Quellcode:
Zeiger := @MyObject;

wird Zeiger die Adresse von der Variablen MyObject zugewiesen
damit hast Du einen Zeiger auf einen Zeiger
und in dem Fall auf die lokale variable

Noch mal:
Das geht nicht

samso 9. Mai 2022 05:58

AW: Pointer auf Instanz zurückgeben
 
Instanz-Variablen sind bereits Referenzen. So wird es funktionieren:

Delphi-Quellcode:
procedure Test(var aObject: TMyClass);
begin
  aObject := TMyClass.Create;
  aObject.Wert := 1234;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  MyObject: TMyClass;
  AnderesObjekt: TMyClass;
begin
  Test(MyObject);
  Caption := MyObject.Wert.ToString; // OK, 1234

  AnderesObjekt := TMyClass.Create;
  AnderesObjekt.Wert := 9876;

  Caption := MyObject.Wert.ToString; // Nun immer noch 1234...

  AnderesObjekt.Free;

  MyObject.Free; // keine AV
end;

idontknow 9. Mai 2022 07:32

AW: Pointer auf Instanz zurückgeben
 
Danke euch beiden!

Ah ja, ok: Mein pObjekt-Zeiger zeigt auf den lokalen Zeiger im Stack, der wiederum auf das Objekt im Heap zeigt. Nach Verlassen der Prozedur Test() wird der lokale Zeiger abgeräumt (das war mir vorher nicht wirklich klar), mein pObjekt-Zeiger wird in Zukunft auf die nächste Variable, die auf dem Stack erzeugt wird, zeigen, und auf das eigentliche Objekt im Heap zeigt gar nichts mehr. Gibt Sinn.

Ich hatte übrigens bisher leider überlesen (*schluck*), das die erwähnte Assembler-Methode gar kein mit

Txyz=class
...
end;

sondern ein mit

Txyz=object
...
end;

erzeugtes Objekt zurückliefert. Und das ist dann offenbar direkt das Objekt, kein Objekt+Zeiger darauf. Wieder was gelernt...

So funktioniert es übrigens:

Delphi-Quellcode:
unit Unit1;

interface

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

type
  TMyClass = object
  public
    Wert: integer;
    procedure Free;
  end;
  PMyClass = ^TMyClass;

  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private-Deklarationen }
  public
    { Public-Deklarationen }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}
procedure Test(var Zeiger: PMyClass);
begin
  New(Zeiger);
  Zeiger^.Wert := 1234;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  pObjekt: PMyClass;
  AnderesObjekt: TMyClass;
  EineBitmap: TBitmap;
begin
  Test(pObjekt);
  Caption := pObjekt^.Wert.ToString; // OK, 1234

//  AnderesObjekt := TMyClass.Create;
//  AnderesObjekt.Wert := 9876;

// Das geht so eh nicht, daher irgendein anderes Objekt zum Testen:
  EineBitmap := TBitmap.Create;

  Caption := pObjekt^.Wert.ToString; // Yeah, 1234...

//  AnderesObjekt.Free;

  EineBitmap.Free;
  pObjekt^.Free;
end;

{ TMyClass }
procedure TMyClass.Free;
begin
  Dispose(@Self);
end;

end.

peterbelow 9. Mai 2022 10:42

AW: Pointer auf Instanz zurückgeben
 
Zitat:

Delphi-Quellcode:
type
  TMyClass = object
  public
    Wert: integer;
    procedure Free;
  end;

Oh man... Diese Art von Object ist schon seit Jahrzehnten deprecated, das stammt noch aus den Zeiten von TurboPascal für Windows und seiner OWL library. Sollte man heutzutage wirklich nicht mehr verwenden, auch wenn Delphi den Typ noch unterstützt.

himitsu 9. Mai 2022 11:46

AW: Pointer auf Instanz zurückgeben
 
Wie schon gesagt wurde, ein "Objekt" ist bereits ein Pointer, könnte also einfach direkt gekastet werden.

Du speicherst dir aber keinen Zeiger auf das Objekt, sondern auf die Variable, in welcher der Objektzeiger gepsiechert ist.
Außerden ist diese Variable auch noch eine lokale Variale auf dem Stack, wobei diese Variable also beim Verlassen der Methode zerstört/ungültig wird.

Auf was dein Zeiger nun zeigt, ist anschließend also "irgenwas", aber nicht mehr diese Variable mit dem Zeiger.


Alle Zeitangaben in WEZ +1. Es ist jetzt 20:35 Uhr.
Seite 1 von 2  1 2      

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