Files |  Tutorials |  Articles |  Links |  Home |  Team |  Forum |  Wiki |  Impressum

Aktuelle Zeit: Do Jul 10, 2025 18:20

Foren-Übersicht » Programmierung » Allgemein
Unbeantwortete Themen | Aktive Themen



Ein neues Thema erstellen Auf das Thema antworten  [ 4 Beiträge ] 
Autor Nachricht
BeitragVerfasst: So Okt 11, 2009 15:58 
Offline
DGL Member

Registriert: Mo Aug 31, 2009 13:19
Beiträge: 151
So, viel von dem, was ich mit der RTTI realisieren wollte klappt mittlerweile, aber dynamische Arrays entziehen sich meiner Macht. Zumindest ab einem bestimmten Punkt. Erstmal Bestandsaufnahme - so weit bin ich:

Code:
  1.  
  2. type
  3.   TMyArray = Array of Integer;
  4.   PMyArray = ^TMyArray;
  5.  
  6.   TMyClass = class(TPersistent)
  7.     private
  8.     FMyArray: TMyArray;
  9.     published
  10.     Property MyArray: TMyArray read FMyArray write FMyArray;
  11.     public
  12.     Constructor Create;
  13.   end;
  14.  
  15. Constructor TMyClass.Create;
  16. var
  17.   PropInfo:   PPropInfo;
  18.   PMyArray:   Pointer;
  19.   Data:       Variant;
  20.   TestArray:  TMyArray;
  21.   Count, i:   Integer;
  22. begin
  23. inherited Create;
  24.  
  25. SetLength(FMyArray, 3);
  26. FMyArray[0] := 0;
  27. FMyArray[1] := 1;
  28. FMyArray[2] := 2;
  29.  
  30. PropInfo := GetPropInfo(Self, 'MyArray');
  31. if PropInfo = nil then Exit;
  32.  
  33. Form1.ListBox1.Items.Add(PropInfo^.Name);
  34. PMyArray := Pointer(GetOrdProp(Self, PropInfo));
  35. DynArrayToVariant(Data, PMyArray, PropInfo^.PropType^);
  36. TestArray := TMyArray(Data);
  37. Form1.ListBox1.Items.Add(IntToStr(Length(TestArray)));
  38.  
  39. Destroy;
  40. end;
  41.  


Der Constructor dient natürlich nur dem Testen...
Das klappt soweit, alle Ausgaben laufen wie geplant.
Nun sieht man aber schon, dass der Sache die Flexibilität fehlt- Lieber wäre es mir (Klartext: Alles andere ist schön anzusehen aber für mich völlig unbrauchbar), die Typinformationen als PPropList mit GetPropList auszulesen. Ums gleich vorwegzunehmen, auch das funktioniert - aber nur, solange das Array undimensioniert ist. Zur Veranschaulichung nochmal das eigentlich gleiche Codebeispiel, nur das es diesmal knallt:

Code:
  1.  
  2. Constructor TMyClass.Create;
  3. var
  4.   PropInfos:  PPropList;
  5.   PMyArray:   Pointer;
  6.   Data:       Variant;
  7.   OrdValue:   Integer;
  8.   Count, i:   Integer;
  9. begin
  10. inherited Create;
  11.  
  12. SetLength(FMyArray, 3);
  13. FMyArray[0] := 0;
  14. FMyArray[1] := 1;
  15. FMyArray[2] := 2;
  16.  
  17. Count := GetPropList(Self.ClassInfo, tkAny, PropInfos);
  18. for i := 0 to Count - 1 do
  19.   Form1.ListBox1.Items.Add(PropInfos^[i]^.Name);
  20.  
  21. Destroy;
  22. end;
  23.  


Schon kommts zu ner Zugriffsverletzung irgendwo im Programm (welches, wie ihr euch sicherlich denken könnt nicht sonderlich groß ist). Grund ist laut Fehlermeldung ein Lesezugriff auf 9E0C7373 (Sollte mir die Speicheraddresse was sagen?)
Kommentier ich den Block um das SetLength herum aus, funktioniert wieder alles bestens.
Heißt für mich, ich kann auf meinen Array nur zugreifen, wenn ich entweder a) den Array noch nicht dimensioniert habe oder b) den Namen von vorn herein kenne.
Leider kommen beide Optionen für mich nicht in Frage.

Hat irgendjemand Erfahrungen mit der Angelegenheit, Denkanstöße oder sowas?

Edit: Ich finds fast schon peinlich, dass sich das so schnell wieder erledigt hat...
Also, das Problem ist gelöst, und ich will euch die Lösung nicht vorenthalten:

Code:
  1.  
  2. Count := GetPropList(Self.ClassInfo, tkAny, nil);
  3. GetMem(PropInfos, Count * SizeOf(PPropInfo));
  4. try
  5. for i := 0 to Count - 1 do
  6.   Form1.ListBox1.Items.Add(PropInfos^[i]^.Name);
  7. finally
  8.   FreeMem(PropInfos, Count * SizeOf(PPropInfo));
  9. end;
  10.  


Eine Frage bleibt bei mir - warum ändert die "manuelle" Speicherverwaltung das Problem, und was macht Delphi bei der "automatischen" Speicherverwaltung falsch?

Nachtrag 2: Und kann mir vielleicht jemand erklären, wo PMyArray hinzeigt, und ob ich irgendwie ohne den Typecast DynArrayToVariant an mein Array kommen kann? Denn dieser Typecast funktioniert nicht, wenn das Array Objekte enthält, und genau darum gehts mir in meinem Ursprungsproblem. Leider funktionierts auch nicht mit Arrays von Pointern (was ich nicht verstehe, denn Pointer sind doch eigentlich nur Integerwerte), sonst könnt ich um das PRoblem drumrum arbeiten...


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: So Okt 11, 2009 21:35 
Offline
DGL Member
Benutzeravatar

Registriert: Di Okt 03, 2006 14:07
Beiträge: 1277
Wohnort: Wien
Zitat:
Eine Frage bleibt bei mir - warum ändert die "manuelle" Speicherverwaltung das Problem, und was macht Delphi bei der "automatischen" Speicherverwaltung falsch?

Nachtrag 2: Und kann mir vielleicht jemand erklären, wo PMyArray hinzeigt, und ob ich irgendwie ohne den Typecast DynArrayToVariant an mein Array kommen kann?


Der untenstehende Code soll das Ganze ein wenig verdeutlichen.
PMyArray1 zeigt auf TMyArray. Da TMyArray selber ein Pointer ist, hast Du jetzt bloß einen Pointer auf einen Pointer. Überdies hast Du, wenn ich mich nicht irre, PMyArray oben doppelt definiert. So was ist immer gefährlich.
PMyArray2 zeigt auf die erste belegte Speicherstelle des MyArray:

Code:
  1. Procedure Tform1.Formcreate(Sender: Tobject);
  2. Type
  3.    TMyArray = Array Of Integer;
  4.    PMyArray = ^TMyArray;
  5. Var
  6.    MyArray: TMyArray;
  7.    PMyArray1: PMyArray;
  8.    PMyArray2: PInteger;
  9. Begin
  10.    SetLength(MyArray,3);
  11.  
  12.    PMyArray1:= @MyArray;
  13.    PMyArray2:= @MyArray[0];
  14.  
  15.    Finalize(MyArray);
  16. End;


Wenn Du den Debugger drüberlaufen lässt, wirst Du sehen, dass PMyArray1 <> PMyArray2. Um an die Daten zu kommen, musst Du PMyArray2 benutzen.

Ein kleiner Hinweis: ich habe mal eine Unit "RTTI.pas" geschrieben, man kann sie immer noch auf Taks SVN-Server finden und sie ist auch getestet und ich bin bekannt für meinen leicht lesbaren Code :) :
http://www.linuxprofessionals.org/wsvn/filedetails.php?repname=dglgui&path=%2Fsandbox%2Ftraude%2FdglRTTI.pas&rev=121

Die Daten müssen geöffnet werden mit "TRTTI_Handler.OpenRTTI(AClient: TObject);" und demgemäß mit "TRTTI_Handler.CloseRTTI;" wieder geschlossen werden (siehe dort).

Ist mir eine Befriedigung wenn mal jemand fragt, denn als ich diese Unit geschrieben hatte, sagte man mir, das wäre Zeitverschwendung, denn es wird dem ursprünglichen Code keine Funktionalität hinzugefügt. Dem kann ich aber nicht zustimmen: Lesbarkeit bzw. Verständlichkeit ist ein Wert an sich. Die nackten Informationen in der Unit TypInfo sind ein wenig gewöhnungsbedürftig.

Viele Grüße,
Traude


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: So Okt 11, 2009 22:16 
Offline
DGL Member
Benutzeravatar

Registriert: Do Sep 02, 2004 19:42
Beiträge: 4158
Programmiersprache: FreePascal, C++
Es ist leider so, dass die RTTI von Delphi / FreePascal bei Arrays sehr eingeschränkt beziehungsweise garnicht funktioniert. Wie du vielleicht festgestellt hast, kannst du auch kein Array direkt publizieren.

Wenn es immer noch um das Laden / Speichern von Daten geht, kann man die Arrays in Objekte kapseln, die dann so etwas wie LoadFromStream/SaveToStream implementieren, man also den Lade-/Speicherauftrag delegieren kann.

greetings

_________________
If you find any deadlinks, please send me a notification – Wenn du tote Links findest, sende mir eine Benachrichtigung.
current projects: ManiacLab; aioxmpp
zombofant networkmy photostream
„Writing code is like writing poetry“ - source unknown


„Give a man a fish, and you feed him for a day. Teach a man to fish and you feed him for a lifetime. “ ~ A Chinese Proverb


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Mo Okt 12, 2009 07:40 
Offline
DGL Member
Benutzeravatar

Registriert: Do Dez 05, 2002 10:35
Beiträge: 4234
Wohnort: Dortmund
Delphi bietet für dynamische "Listen" auch direkt schon ein paar Klassen an. Und zwar heißen die TCollection und TCollectionItem. In der VCL wird für Listen auch nur grundsätzlich solch eine Kombination (davon abgelittene Klassen) benutzt. Allerdings sind die Einträge in solchen Fällen auch meistens etwas koplexer. Also nicht einfach nur ein Integer oder so was. Dadurch relativiert sich der Overhead der durch die Klassen entstehen würde.


Nach oben
 Profil  
Mit Zitat antworten  
Beiträge der letzten Zeit anzeigen:  Sortiere nach  
Ein neues Thema erstellen Auf das Thema antworten  [ 4 Beiträge ] 
Foren-Übersicht » Programmierung » Allgemein


Wer ist online?

Mitglieder in diesem Forum: 0 Mitglieder und 7 Gäste


Du darfst keine neuen Themen in diesem Forum erstellen.
Du darfst keine Antworten zu Themen in diesem Forum erstellen.
Du darfst deine Beiträge in diesem Forum nicht ändern.
Du darfst deine Beiträge in diesem Forum nicht löschen.
Du darfst keine Dateianhänge in diesem Forum erstellen.

Suche nach:
Gehe zu:  
  Powered by phpBB® Forum Software © phpBB Group
Deutsche Übersetzung durch phpBB.de
[ Time : 0.008s | 16 Queries | GZIP : On ]