Ist es eine schlechte Übung, dynamische Arrays zu ändern, die darauf verweisen?

8

Ich habe ein wenig auf dynamische Arrays in D2 geschaut und fand sie sehr schwierig zu verstehen. Es scheint auch, ich interpretiere die Spezifikation falsch. Die Arbeit an einer Referenz oder Scheibe eines dynamischen Arrays scheint sehr fehleranfällig zu sein, wenn die Arrays geändert werden ... Oder verstehe ich einfach nicht die Grundlagen?

Mit Bezug auf das gleiche Array werden nur die tatsächlichen Elemente geteilt:

%Vor%

Wenn sie auf das gleiche Array verweisen, ändert sich das eine durch das andere:

%Vor%

Aus der Spezifikation für das Array

  

Um die Effizienz zu maximieren, versucht die Laufzeitumgebung immer, die Größe zu ändern   Array an Ort und Stelle, um zusätzliches Kopieren zu vermeiden. Es wird immer eine Kopie machen   wenn die neue Größe größer ist und das Array nicht über die   neuer Operator oder ein vorheriger   Größe ändern.

Wenn Sie also die Länge ändern, wird der Verweis nicht unnötig unterbrochen:

%Vor%

Aus der Spezifikation für das Array

  

Die Verkettung erstellt immer eine Kopie ihrer Operanden, selbst wenn einer der Operanden ein 0-Längen-Array ist

%Vor%

Aber wenn die Arrays aufeinander treten, werden die Werte an einen neuen Ort kopiert und die Referenz gebrochen:

%Vor%

Das Ändern der Länge beider Arrays vor einer Änderung führt zu dem gleichen Ergebnis wie oben (ich würde dies unter den obigen Bedingungen erwarten):

%Vor%

Und das Gleiche, wenn man die Länge ändert oder verkettet (ich würde dies unter den obigen Bedingungen erwarten):

%Vor%

Aber dann kommen auch Scheiben ins Bild, und plötzlich ist es noch komplizierter! Die Scheiben könnten verwaist sein ...

%Vor%

Also ... Ist es eine schlechte Übung, mehrere Referenzen auf dasselbe dynamische Array zu haben? Und Scheiben herumliegen usw.? Oder bin ich einfach hier draußen, fehlt der ganze Punkt von dynamischen Arrays in D?

    
simendsjo 05.08.2010, 15:59
quelle

2 Antworten

10

Im Großen und Ganzen scheinen Sie die Dinge ziemlich gut zu verstehen, aber Sie scheinen den Zweck der Eigenschaft ptr falsch zu verstehen. Es gibt nicht an, ob zwei Arrays auf dieselbe Instanz verweisen. Was es tut ist, Sie an den Zeiger zu bekommen, was ist das C-Array darunter. Ein Array in D hat sein length als Teil davon, es ist also eher eine Struktur mit einer Länge und einem Zeiger auf ein C-Array als ein C-Array. Mit ptr können Sie das C-Array abrufen und an C- oder C ++ - Code übergeben. Sie sollten es wahrscheinlich für nichts in reinem D-Code verwenden. Wenn Sie testen möchten, ob zwei Array-Variablen auf dieselbe Instanz verweisen, verwenden Sie den Operator is (oder !is , um zu überprüfen, ob es sich um verschiedene Instanzen handelt):

%Vor%

All das ptr , das für zwei Arrays gleich ist, würde anzeigen, dass sich ihr erstes Element an derselben Stelle im Speicher befindet. Insbesondere könnten ihre length s abweichen. Es bedeutet jedoch, dass sich überlappende Elemente in beiden Arrays geändert werden, wenn Sie sie in einem von ihnen ändern.

Wenn Sie length eines Arrays ändern, versucht D, die Neuzuweisung zu vermeiden, aber es könnte sich für eine Neuzuordnung entscheiden, sodass Sie sich nicht unbedingt darauf verlassen können, ob es neu zugewiesen wird oder nicht. Zum Beispiel wird es neu zugeordnet werden, wenn dies nicht tun wird auf anderen Speicher des Arrays stampfen (einschließlich derjenigen, die den gleichen Wert für ptr haben). Es kann auch neu zugeordnet werden, wenn nicht genügend Speicher vorhanden ist, um die Größe zu ändern. Grundsätzlich wird es neu zugewiesen, wenn dies nicht geschieht, wird auf den Speicher eines anderen Arrays stampfen, und es kann oder kann nicht anders neu zuweisen. Daher ist es im Allgemeinen keine gute Idee, sich darauf zu verlassen, ob ein Array neu zugeordnet wird oder nicht, wenn Sie length einstellen.

Ich hätte erwartet, dass das Anhängen immer nach den Dokumenten kopiert würde, aber bei Ihren Tests scheint es so zu funktionieren, wie es length tut (ich weiß nicht, ob das bedeutet, dass die Dokumente aktualisiert werden müssen oder ob es das ist ein Fehler - ich vermute, dass die Dokumente aktualisiert werden müssen. In beiden Fällen können Sie sich nicht darauf verlassen, dass andere Referenzen auf dieses Array nach dem Anhängen immer noch auf dasselbe Array verweisen.

Wie für Slices funktionieren sie wie erwartet und werden in D - vor allem in der Standardbibliothek Phobos - sehr häufig verwendet. Ein Slice ist ein Bereich für ein Array und Bereiche sind ein Kernkonzept in Phobos. Wie bei vielen anderen Bereichen auch, kann das Ändern des Containers, für den der Bereich / Ausschnitt bestimmt ist, diesen Bereich / Abschnitt ungültig machen. Wenn Sie also Funktionen verwenden, die die Größe von Containern in Phobos ändern können, müssen Sie die Funktionen verwenden, die mit stable vorangestellt sind (zB stableRemove() oder stableInsert() ), wenn Sie nicht riskieren wollen, die Bereiche, die Sie benötigen, ungültig zu machen Container.

Ein Segment ist auch ein Array, genau wie das Array, auf das es zeigt. Natürlich wird die Änderung von length oder das Anhängen an sie allen denselben Regeln folgen wie die Änderung von length oder das Anhängen an ein anderes Array, und es könnte daher neu zugewiesen werden und kein Slice mehr sein in ein anderes Array.

Sie müssen sich nur darüber im Klaren sein, dass eine Änderung der length eines Arrays in irgendeiner Weise zu einer Neuzuweisung führen kann. Daher müssen Sie dies vermeiden, wenn Referenzen weiterhin auf dieselbe Array-Instanz verweisen sollen . Und wenn Sie unbedingt sicherstellen müssen, dass nicht auf dieselbe Referenz verweist, müssen Sie dup verwenden, um eine neue Kopie des Arrays zu erhalten. Wenn Sie sich nicht mit dem length eines Arrays herumschlagen, werden Array-Referenzen (seien es Slices oder Verweise auf das gesamte Array) weiterhin glücklich auf dasselbe Array verweisen.

BEARBEITEN: Es stellt sich heraus, dass die Dokumente aktualisiert werden müssen. Alles, was die Größe des Arrays ändern könnte, wird versuchen, es an Ort und Stelle zu setzen, wenn es möglich ist (es kann also nicht neu zugeordnet werden), aber es wird neu zugewiesen, wenn es nicht im Speicher eines anderen Arrays stampfen oder wenn es nicht genügend Platz hat neu zuweisen. Daher sollte es keinen Unterschied zwischen der Größenänderung des Arrays geben, indem die Eigenschaft length festgelegt und die Größe durch Anhängen geändert wird.

ADDENDUM: Jeder, der D verwendet, sollte diesen Artikel zu Arrays und Slices lesen . Es erklärt sie ziemlich gut und sollte Ihnen eine viel bessere Vorstellung davon geben, wie Arrays in D funktionieren.

    
Jonathan M Davis 05.08.2010, 18:12
quelle
2

Ich wollte das nicht wirklich zu einer vollständigen Antwort machen, aber ich kann die vorherige Antwort noch nicht kommentieren.

Ich denke, dass Verkettung und Anhängen zwei leicht unterschiedliche Operationen sind. Wenn Sie ~ mit einem Array und einem Element verwenden, hängt es an; mit zwei Arrays ist es Verkettung.

Sie können dies stattdessen versuchen:

%Vor%

Und sehen Sie, ob Sie die gleichen Ergebnisse erhalten.

Wenn Sie ein definiertes Verhalten haben möchten, verwenden Sie einfach die Eigenschaften .dup (oder .idup für immutables). Dies ist auch sehr nützlich, wenn Sie ein Array von Referenzen haben; Sie können das Haupt-Array und die dup-Slices modifizieren, um weiter zu arbeiten, ohne sich um die Rennbedingungen kümmern zu müssen.

EDIT: ok, ich habe es ein bisschen falsch verstanden, aber da ist es trotzdem. Verkettung! = Anhängen.

// Max

    
awishformore 05.08.2010 19:01
quelle

Tags und Links