AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Sprachen und Entwicklungsumgebungen Sonstige Fragen zu Delphi Delphi Objekt in Array kopieren und anschließend freigeben
Thema durchsuchen
Ansicht
Themen-Optionen

Objekt in Array kopieren und anschließend freigeben

Ein Thema von blackdrake · begonnen am 30. Aug 2008 · letzter Beitrag vom 1. Sep 2008
Antwort Antwort
Seite 2 von 3     12 3      
Hansa

Registriert seit: 9. Jun 2002
Ort: Saarland
7.554 Beiträge
 
Delphi 8 Professional
 
#11

Re: Objekt in Array kopieren und anschließend freigeben

  Alt 31. Aug 2008, 02:58
Für solche Sachen enthält die TObjectList schließlich "OwnsObjects". In weiser Voraussicht haben sie das standardmäßig schon auf true gesetzt. Ist schon recht interessant, was man damit alles zusammenbauen kann. Und kaum einer weiß es.
Gruß
Hansa
  Mit Zitat antworten Zitat
Benutzerbild von Luckie
Luckie

Registriert seit: 29. Mai 2002
37.621 Beiträge
 
Delphi 2006 Professional
 
#12

Re: Objekt in Array kopieren und anschließend freigeben

  Alt 31. Aug 2008, 03:19
Zitat von Hansa:
Für solche Sachen enthält die TObjectList schließlich "OwnsObjects". In weiser Voraussicht haben sie das standardmäßig schon auf true gesetzt. Ist schon recht interessant, was man damit alles zusammenbauen kann. Und kaum einer weiß es.
Nun ja, die Hilfe weiß es und es soll auch Programmierer geben, die da auch mal reingucken. :mrgrren:
Michael
Ein Teil meines Codes würde euch verunsichern.
  Mit Zitat antworten Zitat
Medium

Registriert seit: 23. Jan 2008
3.685 Beiträge
 
Delphi 2007 Enterprise
 
#13

Re: Objekt in Array kopieren und anschließend freigeben

  Alt 31. Aug 2008, 04:56
Um mal auf deine Originalfragen noch einzugehen:

Zitat von blackdrake:
Anschließend gebe ich Submission frei. Und dies verursacht bei mir eine AV bei allen zukünftigen Zugriffen auf die Array-Elemente und deren Eigenschaften.
Anders als bei Records wird bei Objekten stets "by reference" zugegriffen, und eine Zuweisung an eine andere Variable macht da keinen Unterschied. Submissions und das Array-Element dem du Submissions zugewiesen hast, zeigen beide auf den selben Speicherbereich. Das Objekt gibt es nach wie vor nur ein einziges Mal, du zeigst aber zwei mal darauf.

Zitat von blackdrake:
Kommentiere ich die Zeile "Submission.Free" aus, funktioniert alles. Dies erachte ich jedoch als ein Problem, da der Speicher nicht freigegeben wird. Was passiert hier? Wieso wird in der Funktion AddToArray() keine Kopie der TSubmission-Instanz gemacht, die in den Array wandert? Wieso gehen die Array-Elemente kaputt, wenn ich das Originalstück freigebe?
Wenn du Submissions frei gibst, wird der Speicher auf den die Variable zeigt freigegeben. Das ist aber nun genau der selbe Bereich auf den das Array-Element zeigt, wodurch Zugriffe auf dieses dann eben im Nirvana landen. Es wird bei Objekten prinzipiell erst einmal nie etwas kopiert, es sei denn man kümmert sich ganz explizit draum.

Zitat von blackdrake:
Bei Strings, die als Variable in eine Funktion wandern, kenne ich die Routine UniqueString(). Hier muss ich mein TSubmission irgendwie auch "einzigartig" machen, oder?
Nein. Einfach Klasseninstanzen (=Objekte) die noch verwendet werden nicht freigeben. Dabei musst du eben zwischen dem eigentlichen Objekt welches irgendwo auf dem Heap sitzt, und den Variablen unterscheiden, die immer nur ein Zeiger auf diese Stelle auf dem Heap sind unterscheiden.


Prinzipiell ist es aber auch völlig richtig TObjectList einzusetzen. Ein Array ist für das was du dort vor hast recht ungeeignet.
"When one person suffers from a delusion, it is called insanity. When a million people suffer from a delusion, it is called religion." (Richard Dawkins)
  Mit Zitat antworten Zitat
blackdrake

Registriert seit: 22. Aug 2003
Ort: Bammental
618 Beiträge
 
Delphi 10.3 Rio
 
#14

Re: Objekt in Array kopieren und anschließend freigeben

  Alt 31. Aug 2008, 14:02
Hallo.

Danke für eure Antworten.

Ich habe jetzt den Array entfernt und durch eine abgeleitete Objektliste ersetzt. Jetzt erhalte ich eine AV, die ich absolut nicht verstehe.

Wenn ich mit die Objektliste x befülle und freigebe, funktioniert alles.

Gebe ich die Objektliste x in eine Funktion, die eine zweite Liste y erstellt, kommt eine AV bei Freigabe von x:

Delphi-Quellcode:
function MachWas(Input: TSubmissionObjectList): TSubmissionObjectList;
var
  i: integer;
begin
  result := TSubmissionObjectList.Create;

  for i := 0 to Input.Count - 1 do
  begin
    if odd(i) then
    begin
      result.Add(Input.Items[i]);
    end;
  end;
end;

procedure TForm1.FormCreate(Sender: TObject);
var
  x, y: TSubmissionObjectList;
  sub: TSubmission;
  i: integer;
begin
  x := TSubmissionObjectList.Create;
  try
    for i := 0 to 100 do
    begin
      sub := TSubmission.Create;
      sub.MD5 := 'Test'+IntToStr(i);
      x.Add(sub);
    end;

    // Ist dieser Abschnitt auskommentiert, keine AV bei x.Free;
    y := MachWas(x);
    try

    finally
      y.Free;
    end;

  finally
    x.Free; // AccessViolation durch y.Free!
  end;
end;
Zur schnellen Rekonstruktion noch folgender Zusatzcode mit Deklarationen:

Delphi-Quellcode:
type
  TSubmission = class(TObject)
    Tags: string;
    Rating: string;
    Score: integer;
    PictureNumber: integer;
    MD5: string;
  end;

  TSubmissionObjectList = class(TObjectList)
  protected
    function getItem(Index: Integer): TSubmission; virtual;
    procedure setItem(Index: Integer; Objekt: TSubmission); virtual;
  public
    function Add(Objekt: TSubmission): Integer; virtual;
    function Remove(Objekt: TSubmission): Integer; virtual;
    function IndexOf(Objekt: TSubmission): Integer; virtual;
    procedure Insert(Index: Integer; Objekt: TSubmission); virtual;
    function First: TSubmission; virtual;
    function Last: TSubmission; virtual;
    property Items[index: Integer]: TSubmission read getItem write setItem; default;
  end;

function TSubmissionObjectList.getItem(Index: Integer): TSubmission;
begin
  Result := TSubmission(inherited Items[Index]);
end;

procedure TSubmissionObjectList.setItem(Index: Integer; Objekt: TSubmission);
begin
  inherited Items[Index] := Objekt;
end;

function TSubmissionObjectList.Add(Objekt: TSubmission): Integer;
begin
  Result := inherited Add(Objekt);
end;

function TSubmissionObjectList.First: TSubmission;
begin
  Result := TSubmission(inherited First());
end;

function TSubmissionObjectList.IndexOf(Objekt: TSubmission): Integer;
begin
  Result := inherited IndexOf(Objekt);
end;

procedure TSubmissionObjectList.Insert(Index: Integer; Objekt: TSubmission);
begin
  inherited Insert(Index, Objekt);
end;

function TSubmissionObjectList.Last: TSubmission;
begin
  Result := TSubmission(inherited Last());
end;

function TSubmissionObjectList.Remove(Objekt: TSubmission): Integer;
begin
  Result := inherited Remove(Objekt);
end;
Ich befürchte, das hat wieder was damit zu tun, da Objekte nur referenziert und nicht kopiert werden. Ich weiß irgendwie nicht mehr weiter

Gruß
blackdrake
Daniel Marschall
  Mit Zitat antworten Zitat
Benutzerbild von DeddyH
DeddyH

Registriert seit: 17. Sep 2006
Ort: Barchfeld
27.619 Beiträge
 
Delphi 12 Athens
 
#15

Re: Objekt in Array kopieren und anschließend freigeben

  Alt 31. Aug 2008, 14:08
Deine Vermutung ist richtig. Dadurch, dass Du die Objekte (besser gesagt, deren Referenzen) in die 2. Liste packst und diese dann freigibst, zeigen die entsprechenden Objektreferenzen der 1. Liste dann ins Leere.
Detlef
"Ich habe Angst vor dem Tag, an dem die Technologie unsere menschlichen Interaktionen übertrumpft. Die Welt wird eine Generation von Idioten bekommen." (Albert Einstein)
Dieser Tag ist längst gekommen
  Mit Zitat antworten Zitat
blackdrake

Registriert seit: 22. Aug 2003
Ort: Bammental
618 Beiträge
 
Delphi 10.3 Rio
 
#16

Re: Objekt in Array kopieren und anschließend freigeben

  Alt 31. Aug 2008, 14:12
Hallo.

Und was macht man dagegen?

Ich kann weder auf y.Free, noch auf x.Free verzichten, da ich sonst MemoryLeaks habe.

Vielleicht könnte man TSubmissionObjectList.Add() frisieren, sodass es die Objekte vorher dupliziert und dann das Duplikat hinzufügt?

Die resultierende Liste y sollte eigentlich von Liste x unabhängig abhängig sein. Wie mache ich das am geschicktesten?

Gruß
blackdrake
Daniel Marschall
  Mit Zitat antworten Zitat
Apollonius

Registriert seit: 16. Apr 2007
2.325 Beiträge
 
Turbo Delphi für Win32
 
#17

Re: Objekt in Array kopieren und anschließend freigeben

  Alt 31. Aug 2008, 14:16
Du könntest in der Liste, die MachWas zurückgibt, OwnsObjects auf False setzen. Dann wird es allerdings wieder problematisch, falls du y neue Objekte hinzufügst.
Am besten ist wohl, TSubmission von TPersistent abzuleiten und Assign zu überschreiben. In MachWas könntest du dann die Objekte klonen.

Mir fällt gerade noch eine weitere Lösung ein: Du könntest auch ein ISubmission-Interface deklarieren und die Submissions in einer TInterfaceList speichern. Die automatische Referenzzählung würde dich dann von der Pflicht befreien, die Submissions manuell freizugeben.
Wer erweist der Welt einen Dienst und findet ein gutes Synonym für "Pointer"?
"An interface pointer is a pointer to a pointer. This pointer points to an array of pointers, each of which points to an interface function."
  Mit Zitat antworten Zitat
blackdrake

Registriert seit: 22. Aug 2003
Ort: Bammental
618 Beiträge
 
Delphi 10.3 Rio
 
#18

Re: Objekt in Array kopieren und anschließend freigeben

  Alt 31. Aug 2008, 14:35
Hallo.

Ich würde es vorziehen, die TSubmissionObjectList zu modifizieren, sodass sie neue Objekte dupliziert und man somit eine unabhängige Liste erzeugen kann. Dann müsste ich mich nur 1 Mal direkt in der TSubmissionObjectList um diese Angelegenheit kümmern, anstelle jede Funktion umzuschreiben, die mit TSubmissionObjectList arbeiten. Ist doch korrekt so, oder?

Ich habe jetzt folgendermaßen geändert:

Delphi-Quellcode:
type
  TSubmission = class(TPersistent)
  public
    Tags: string;
    Rating: string;
    Score: integer;
    PictureNumber: integer;
    MD5: string;
    procedure Assign(Source: TPersistent); override;
  end;

procedure TSubmission.Assign(Source: TPersistent);
begin
  inherited; // Was soll ich hier machen?
end;

function TSubmissionObjectList.Add(Objekt: TSubmission): Integer;
var
  Duplikat: TSubmission;
begin
  Duplikat:= TSubmission.Create;
  Duplikat.Assign(Objekt);
  Result := inherited Add(Duplikat);
end;
Fehlermeldung: 'TSubmission kann nicht zu TSubmission zugewiesen werden'.

Du schriebst, dass ich Assign() überschreiben müsste. Was muss ich denn genau am Code ändern, sodass Assign an mein TSubmission angepasst wird? Der Sourcecode von TPersistent.Assign() hat mir irgendwie nicht die geistige Erleuchtung gebracht.

-- Zu deinem Nachtrag: Ich werde das mit dem Interface gleich mal in einem zweiten Testprojekt ausprobieren.

Gruß
blackdrake
Daniel Marschall
  Mit Zitat antworten Zitat
blackdrake

Registriert seit: 22. Aug 2003
Ort: Bammental
618 Beiträge
 
Delphi 10.3 Rio
 
#19

Re: Objekt in Array kopieren und anschließend freigeben

  Alt 31. Aug 2008, 14:45
Zitat von Apollonius:
Mir fällt gerade noch eine weitere Lösung ein: Du könntest auch ein ISubmission-Interface deklarieren und die Submissions in einer TInterfaceList speichern. Die automatische Referenzzählung würde dich dann von der Pflicht befreien, die Submissions manuell freizugeben.
Moment, das geht doch gar nicht. Mein TSubmission enthält 3 Strings und 2 Integer. Ein Interface darf aber nur nicht-implementierte Methoden enthalten und keine Felddeklarationen.
Daniel Marschall
  Mit Zitat antworten Zitat
Apollonius

Registriert seit: 16. Apr 2007
2.325 Beiträge
 
Turbo Delphi für Win32
 
#20

Re: Objekt in Array kopieren und anschließend freigeben

  Alt 31. Aug 2008, 14:46
Die klassische Implementation von Assign sieht so aus:
Delphi-Quellcode:
procedure TMeinObjekt.Assign(Source: TPersistent);
begin
  if Source is TMeinObjekt then
  begin
    Feld1 := TMeinObjekt(Source).Feld1;
    Feld2 := TMeinObjekt(Source).Feld2;
    Feld3 := TMeinObjekt(Source).Feld3;
    Feld4 := TMeinObjekt(Source).Feld4;
  end
  else
    inherited;
end;
Du musst also einfach die Felder von Hand kopieren. Lediglich bei Feldern, die selbst Objekte beinhalten, solltest du überlegen, ob du nicht wiederum Assign verwendest, falls die Klasse es implementiert.

Bezüglich Interfaces: Dann musst du Properties mit Get- und Set-Methoden verwenden. Das ist allerdings etwas Schreibarbeit.
Wer erweist der Welt einen Dienst und findet ein gutes Synonym für "Pointer"?
"An interface pointer is a pointer to a pointer. This pointer points to an array of pointers, each of which points to an interface function."
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 2 von 3     12 3      


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 04:37 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