AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Thema durchsuchen
Ansicht
Themen-Optionen

Interessantes Destruktor Problem

Ein Thema von sx2008 · begonnen am 7. Jan 2011 · letzter Beitrag vom 7. Jan 2011
Antwort Antwort
Seite 2 von 2     12   
mkinzler
(Moderator)

Registriert seit: 9. Dez 2005
Ort: Heilbronn
39.861 Beiträge
 
Delphi 11 Alexandria
 
#11

AW: Interessantes Destruktor Problem

  Alt 7. Jan 2011, 10:08
Auch wenn es in diesem Beispiel geht, da ja Stream ein übergebener Parameter ist, sollte man die Reihenfolge konsequent einhalten.
Denn somst könnte es bei späteren Änderungen im Code zu Missverständnissen führen.
Ich würde auch zudem keine "externen" Objekte in einem Konstruktor erzeugen.
Markus Kinzler
  Mit Zitat antworten Zitat
Benutzerbild von Uwe Raabe
Uwe Raabe
Online

Registriert seit: 20. Jan 2006
Ort: Lübbecke
11.477 Beiträge
 
Delphi 12 Athens
 
#12

AW: Interessantes Destruktor Problem

  Alt 7. Jan 2011, 10:09
Naja trotzdem sollte man so nicht programmieren. Nach dem inherited wurden alle Objekte der Basisklasse(n) schon freigegeben (davon ausgegangen, dass die Basisklassen sauber programmiert wurden). Da kann man böse auf die Nase fallen.
Natürlich muss man wissen, was man tut - das gilt immer und überall beim Programmieren. Es kann ja durchaus sein, daß im inherited eine virtuelle Methode aufgerufen wird, die in einer abgeleiteten Version auf einige der Instanz-Felder zugreift. Dann müssen diese Felder während des inherited Destroy noch gültig sein. TList ruft z.B. im Destroy ein Clear auf, das in einer abgeleiteten Klasse überschrieben sein kann und auf irgendwelche Felder in dieser abgeleiteten Klasse zugreift. (Interessanterweise ruft TList.Destroy gar kein inherited auf!)

Die Aussage "man sollte so nicht programmieren" kann ich also in keiner Weise nachvollziehen.

Nur ein paar Beispiele aus Classes.pas:

Delphi-Quellcode:
destructor TRegGroup.Destroy;
destructor TThreadList.Destroy;
destructor TStringList.Destroy;
destructor TThread.Destroy;
destructor TBasicAction.Destroy;
destructor TDataModule.Destroy;
Uwe Raabe
Certified Delphi Master Developer
Embarcadero MVP
Blog: The Art of Delphi Programming
  Mit Zitat antworten Zitat
Benutzerbild von Bummi
Bummi

Registriert seit: 15. Jun 2010
Ort: Augsburg Bayern Süddeutschland
3.470 Beiträge
 
Delphi XE3 Enterprise
 
#13

AW: Interessantes Destruktor Problem

  Alt 7. Jan 2011, 10:14
Delphi-Quellcode:
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type

  TMyObject = class
  Private
    FMyTest:TStringList;
    function GetInfo: String;
  public
    destructor Destroy; override;
    Constructor Create;virtual;
    procedure FreeInstance; override;
    Property Info:String Read GetInfo;
  end;
  TMyObject2 = class(TMyObject)
  public
    destructor Destroy; override;
    Constructor Create;override;
    procedure FreeInstance; override;
 end;
  TForm1 = class(TForm)
    ADODataSet1: TADODataSet;
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private-Deklarationen }
  public
    { Public-Deklarationen }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
begin
  With TMyObject2.Create do Free;

end;
{ TMyObject }

constructor TMyObject.Create;
begin
  inherited;
  FMyTest:=TStringList.Create;
  FMyTest.Add('Text');
end;

destructor TMyObject.Destroy;
begin
  FMyTest.Free;
  inherited;
end;

procedure TMyObject.FreeInstance;
begin
  inherited;

end;

function TMyObject.GetInfo: String;
begin
   Result := FMyTest.Text;
end;

{ TMyObject2 }

constructor TMyObject2.Create;
begin
  inherited;

end;

destructor TMyObject2.Destroy;
begin
  Showmessage('Vor inherited:' +Info);
  inherited;
  Showmessage('Nach inherited:' +Info);
end;

procedure TMyObject2.FreeInstance;
begin
  inherited;

end;

end.
Thomas Wassermann H₂♂
Das Problem steckt meistens zwischen den Ohren
DRY DRY KISS
H₂ (wenn bei meinen Snipplets nichts anderes angegeben ist Lizenz: WTFPL)
  Mit Zitat antworten Zitat
Benutzerbild von mleyen
mleyen

Registriert seit: 10. Aug 2007
609 Beiträge
 
FreePascal / Lazarus
 
#14

AW: Interessantes Destruktor Problem

  Alt 7. Jan 2011, 10:16
Natürlich muss man wissen, was man tut
...
Die Aussage "man sollte so nicht programmieren" kann ich also in keiner Weise nachvollziehen.
Da haben wir den Knackpunkt. Wenn man zB im Team arbeitet, kann es sein das andere es nicht wissen was derjenige da getan hat, übernimmt aber das inherited immer am Anfang.

Die Frage ist nicht warum man so etwas nicht tun sollte.
Die Frage ist: Gibt es irgend einen Grund warum man sowas machen sollte?
  Mit Zitat antworten Zitat
Benutzerbild von Deep-Sea
Deep-Sea

Registriert seit: 17. Jan 2007
907 Beiträge
 
Delphi XE2 Professional
 
#15

AW: Interessantes Destruktor Problem

  Alt 7. Jan 2011, 10:18
@Bummi:
Und was soll uns der Code zeigen?

@mleyen:
Darum sollte man auch LERNEN wie etwas funktioniert, anstatt einfach irgendeine Aussage von wegen "Es muss so sein, frag nicht warum, es ist halt so!" zu glauben
Und wenn man schon mit so einem Anfänger im Team arbeitet, gibt es ja noch die guten alten Kommentare, um zu erklären, warum hier etwas nach inherited steht obwohl das ja sooo böse ist.
Und einen Grund gibt es auch, dass zu tun: Wenn man z.B. eine von Uwe Raabe genannte Klasse ableiten will, kann es u.U. unerlässlich sein.
Chris
Die Erfahrung ist ein strenger Schulmeister: Sie prüft uns, bevor sie uns lehrt.

Geändert von Deep-Sea ( 7. Jan 2011 um 10:21 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von s.h.a.r.k
s.h.a.r.k

Registriert seit: 26. Mai 2004
3.159 Beiträge
 
#16

AW: Interessantes Destruktor Problem

  Alt 7. Jan 2011, 12:30
Zitat:
Delphi-Quellcode:
inherited; // Könnte ja auf den übergebenen Stream noch zugreifen.
FStream.Free;
Wenn FStream in der TAbgeleiteteKlasse deklariert ist, wie/wieso sollten dann dessen Vorfahre darauf zugreifen? Der Vorfahre kennt FStream doch nicht.
Es ist eher andersrum, also daß TAbgeleiteteKlasse auf Eigenschaften des Vorfahren zugreift.
Und wenn FStream im Vorfahren deklariert ist, dann ist dieser für dessen Erzeugung und Freigabe verantwortlich, womit dieses nicht in den Nachfahren reingehören würde.
Ich weiß echt nicht, warum es hier so viele Diskussionen um sowas geben kann. Genau das war es, an was ich gedacht hatte, als ich den Code und vor allem den Kommentar dazu gelesen hatte. Das widerspricht ganz dezent dem, was ich mir unter OOP vorstelle.
»Remember, the future maintainer is the person you should be writing code for, not the compiler.« (Nick Hodges)
  Mit Zitat antworten Zitat
Benutzerbild von Uwe Raabe
Uwe Raabe
Online

Registriert seit: 20. Jan 2006
Ort: Lübbecke
11.477 Beiträge
 
Delphi 12 Athens
 
#17

AW: Interessantes Destruktor Problem

  Alt 7. Jan 2011, 12:38
Zitat:
Delphi-Quellcode:
inherited; // Könnte ja auf den übergebenen Stream noch zugreifen.
FStream.Free;
Wenn FStream in der TAbgeleiteteKlasse deklariert ist, wie/wieso sollten dann dessen Vorfahre darauf zugreifen? Der Vorfahre kennt FStream doch nicht.
Wie ich an anderer Stelle schon ausgeführt habe: Es kann sein, daß im inherited des Vorfahren eine virtuelle Methode aufgerufen wird, die im Kontext des Nachfahren halt doch auf FStream zugreift. Das Beispiel von TList.Destroy, daß virtuell Clear aufruft kommt in meinen Programmen bestimmt einige Male vor. Würde ich dort das Äquivalent von FStream vor dem inherited schon freigeben, würde das bestenfalls nur Zugriffsverletzungen zur Folge haben.
Uwe Raabe
Certified Delphi Master Developer
Embarcadero MVP
Blog: The Art of Delphi Programming
  Mit Zitat antworten Zitat
Benutzerbild von SirThornberry
SirThornberry
(Moderator)

Registriert seit: 23. Sep 2003
Ort: Bockwen
12.235 Beiträge
 
Delphi 2006 Professional
 
#18

AW: Interessantes Destruktor Problem

  Alt 7. Jan 2011, 12:57
Also ganz in Ordnung finde ich den Code auch nicht allerdings wegen etwas anderem.
Delphi-Quellcode:
constructor TAbgeleiteteKlasse.Create;
begin
  FStream := TMemoryStream.Create;
  inherited Create(FStream);
end;

destructor TAbgeleiteteKlasse.Destroy;
begin
  [...]
  FStream.Free;
end;
Und zwar ist hier ersichtlich das der Constructor der Vorfahrenklasse einen Constructor hat dem ein Stream übergeben wird.
Auch wenn der Constructor der neuen Klasse diesen Parameter nicht mehr hat ist es trotzdem noch möglich den Constructor der Vorfahrenklasse aufzurufen und den Stream zu übergeben. In dem Fall ist es Fatal das im neuen Destructor einfach mein übergebener Stream frei gegeben wird.

Bsp.:
Delphi-Quellcode:
var
  mystream: TStream;
  tmp: TAbgeleiteteKlasse;
begin
  MyStream := TMemoryStream.Create();
  tmp := TAbgeleiteteKlasse.Create(myStream);
  [...]
  tmp.Free;
  //jetzt ist plötlizlich mystream freigegeben obwohl das bei der Vorfahrenklasse noch nicht der Fall war
  [...]
Also ein eindeutiger Designfehler. Das worüber hier die ganze Zeit diskutiert wird kann ich nicht nachvollziehen denn es ist tatsächlich ab und zu der Fall das man erst nach dem inherited im Destructor etwas freigeben kann. Das ist zum Beispiel der Fall wenn im Destructor der Klasse von der man ableitet noch OnChange-Ereignisse/Speichern-Methoden etc. aufgerufen werden die durch Vererbung Dinge aus dem Nachfahren verwenden.
Jens
Mit Source ist es wie mit Kunst - Hauptsache der Künstler versteht's
  Mit Zitat antworten Zitat
Benutzerbild von Deep-Sea
Deep-Sea

Registriert seit: 17. Jan 2007
907 Beiträge
 
Delphi XE2 Professional
 
#19

AW: Interessantes Destruktor Problem

  Alt 7. Jan 2011, 13:01
@SirThornberry:
Es war ja auch nur ein Beispiel, was mir im damaligen Thread spontan eingefallen ist. Über Sinn oder Unsinn einen Konstruktor derart zu überschreiben ging es bei der Diskussion aber auch nie

PS: Der "alte" Konstruktor, der den Stream erwartet, könnte z.B. (strict) protected sein, so kann man ihn nicht so aufrufen, wie in deinem Beispiel ...
Chris
Die Erfahrung ist ein strenger Schulmeister: Sie prüft uns, bevor sie uns lehrt.
  Mit Zitat antworten Zitat
Benutzerbild von SirThornberry
SirThornberry
(Moderator)

Registriert seit: 23. Sep 2003
Ort: Bockwen
12.235 Beiträge
 
Delphi 2006 Professional
 
#20

AW: Interessantes Destruktor Problem

  Alt 7. Jan 2011, 13:14
Achso. Auf jeden Fall ist an dem diskutierten nichts verwerfliches. Wie bereits beschrieben wird der Speicher schließlich vorm Constructor-Aufruf reserviert und nach dem Destructor-Aufruf freigegeben. Und auch in anderen Programmiersprachen ist das nicht viel anders.
Jens
Mit Source ist es wie mit Kunst - Hauptsache der Künstler versteht's
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 2 von 2     12   


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 18:12 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