Zitat von
EWeiss:
Wenn ich kein Array von Zeigern auf den Typ des Records verwende benötige ich kein New() mehr
da ich den Record direkt zur verfügung habe.
Das bedeutet auch ich benötige ebenfalls ZeroMemory nicht mehr.
Hi, mal ein paar Worte zur eigentlichen Frage (die war noch frei von Code glaube ich).
Also erstmal solltest du hier wirklich zwischen Arrays und Records unterscheiden, new wirst du tatsächlich nie direkt im Zusammenhang mit einem Array verwenden müssen/sollen/brauchen. Darauf komme ich aber nachher zurück.
An sich ist ein Array in fast allen Programmiersprachen vorhanden. An sich hat das nichts mit veraltet oder nicht zu tun, die Struktur ist einfach denkbar einfach und hat (je nach Implementierung) sehr wenig Overhead (keine indirection nötig).
Ein Array kannst du dir immer (vereinfacht, wenn auch nicht viel) als ein Stück Speicher vorstellen. Hast du ein Array vom Typ T mit n Elementen, dann würde hier einfach n * sizeOf(T) Speicher reserviert werden (+ 32 Bit für die Größe). Wichtig ist hier aber einfach die Tatsache, dass du nur ein Stück Speicher hast, dass genau die n mal die Struktur T aufnehmen kann und die direkt hintereinander im Speicher liegen (die Ts). Wenn du die Position des ersten Elements im Speicher kennst, dann kannst du genau diese Eigenschaft ausnutzen. Ausgehend von der Position des ersten Elements, liegt das zweite gerade an der Adresse des ersten + sizeOf(T). Würdest du hier + 2*sizeOf(T) addieren, landest du beim dritten Element...
Du kannst hier also ausgehend von der Adresse des ersten Elements direkt die Adresse aller anderen Elemente berechnen. Dies macht Arrays einfach sehr perfomant.
Der Unterschied zwischen einem statischen Array und einem Dynamischen liegt natürlich in der festen Größe des statischen Arrays, aber hier wären noch weitere Unterschiede zu finden. So wird ein statisches Array aut. aus dem Speicher entsorgt und der Index kann an einer beliebigen Stelle beginnen.
Variablen die als dyn. Array deklariert werden speichern nur einen Zeiger auf das Array. Bevor du dein Array nicht mit setLength initialisierst, gibt es hier einfach keinen Speicher, der wirklich zu dem Array gehört. Während der Zeiger bei einer Instanz- oder Globalen-Variable noch initialiert wird (= nil), ist dies innerhalb von Methoden/Funktionen nicht der Fall. Hier könntest du also einen gültigen Zeiger haben, von dem du aber nicht weißt, wo dieser hinzeigt. Ist dein dyn. Array nicht initialisiert, führt jeder Zugriff auf ein Element im Array zu einem zufälligen Speicherzugriff. Beim Lesen wirst du hier nur unerwartete Werte finden, beim Schreiben kann es sein, dass du den Speicher eines anderen Teils deines Programms überschreibst. Nur im besten Fall wirst du das sofort merken, im schlimmsten Fall ist das ein sehr sehr schwer zu lokalisierender Fehler!
Deshalb gilt es immer, dyn. Arrays auch zu initialisieren. Die Länge legst du dabei mit setLength fest und erhälst hier den Zeiger auf das erzeugte, Null indexierte Array. Doch auch hier musst du aufpassen. Da du nur einen Zeiger auf das Array hast, musst du selbst dafür sorgen, dass die dahinter liegenden Daten nicht als unerreichbarer Müll im Speicher bleiben. Es ist immer sauber, dyn. Arrays explizit frei zu geben. Dazu rufst du finalize(<ARRAY>) und setLength(<ARRAY>, 0) auf. Damit stellst du sicher, dass der hier allozierte Speicher sofort (an dieser Stelle) frei gegeben wird.
Das ist eigentlich schon so ziemlich alles was ich zu Arrays sagen wollte (der Rest wurde ja schon ausführlich erklärt).
Dann gibt es noch die Records. Ein Record ist eine einfache Struktur. Auch hier liegen die einzelnen Elemente eingentlich nur direkt hintereinander im Speicher. Du findest hier allerdings häufig auch noch Ausrichtungen im Speicher, aber das ist erstmal egal. Anders als beim Array, kann ein Record sich aus unterschiedlichen Datentypen zusammensetzen.
Das Problem an einem Record ist, dass es immer als ganzes durch den Speicher bewegt wird. Möchtest du ein Record an eine Funktion übergeben, so wird hier das komplette Record übergeben. Da sich ein Record aus verschiedenen Datentypen und aus beliebig vielen Variablen zusammensetzen kann, kannst du hier schnell eine relativ große Struktur erzeugen, deren kopieren entsprechend viel Zeit kostet. Deswegen wird in der imperativen Programmierung häufig mit einem Zeiger auf ein Record gearbeitet. Ein Zeiger ist dabei (auf einem 32 Bit System) immer 32 Bit groß. Dies ist völlig unabhängig von der Größe des Records, auf den dieser Zeiger zeigt (Adressen haben diese feste Größe). Wird nun ein solcher Zeiger übergeben, so müssen nur noch 4 Byte kopiert werden (je nach Record kann dies ein deutlich kleinerer Wert als die Recordgröße bedeuten). Bei der Arbeit mit Zeigern gibt es jedoch verschiedene Dinge zu beachten. Auch hier gilt wieder, dass diese unbedingt initialisiert werden müssen. Es kann sonst leicht zu Problemen kommen. Da ein Zeiger nur die Adresse einer Struktur beinhaltet, wird hier nicht mit einer Kopie des referenzierten Datums gearbeitet. Alle Änderungen an dieser Struktur (Belegung des Records) werden direkt im Speicher der Variablen ausgeführt, sind also quasi-global.
Möchte man eine dyn. Anzahl von Records erzeugen, so hat man hier die Auswahl zwischen verschiedenen Möglichkeiten. Hier kommt new in Spiel. New reserviert Speicher für eine bestimmte Struktur. New ist dabei einfach typsicher, man übergibt einen Zeiger auf die Struktur und new alloziert Speicher in der Größe der dereferenzierten Struktur. Dieser Speicher muss später entsprechend wieder frei gegeben werden.
Mit new lassen sich so dyn. Examplere einer Struktur erzeugen. Wie man diese verwaltet ist wiederum beliebig und unabhängig vom new. Man kann hier ein Array von Zeigern verwalten oder eine TList verwenden (die greift intern wiederum auf Arrays zurück) oder eine andere Lösung wählen.
Aber auch zu new gibt es Alternativen. So kann man auch ein dyn. Array vom Typ der Struktur erzeugen. Dabei wird ausreichen Speicher reserviert um n (Länge des Arrays) Exemplare der Struktur direkt aufzunehmen. Hier sorgt das finalize dann dafür, dass der Speicher auch wieder frei gegeben wird.
Zudem kannst du auch direkt Speicher (einer bestimmten Größe) allozieren und beliebig verwenden. Hierauf möchte ich gar nicht mehr näher eingehen, denn Typsicherheit sollte immer genutzt werden, wenn dies möglich ist.
Gruß Der Unwissende