Ich verstehe, dass die Mitgliedszuweisung von Arrays nicht unterstützt wird, so dass Folgendes nicht funktioniert:
int num1[3] = {1,2,3};
int num2[3];
num2 = num1; // "error: invalid array assignment"
Ich habe dies nur als Tatsache akzeptiert und festgestellt, dass das Ziel der Sprache darin besteht, ein offenes Framework bereitzustellen und den Benutzer entscheiden zu lassen, wie etwas wie das Kopieren eines Arrays implementiert werden soll.
Folgendes funktioniert jedoch:
struct myStruct { int num[3]; };
struct myStruct struct1 = {{1,2,3}};
struct myStruct struct2;
struct2 = struct1;
Das Array num[3]
wird von seiner Instanz in struct1
in seine Instanz in mitgliedsbezogen zugewiesen struct2
.
Warum wird die Mitgliederzuweisung von Arrays für Strukturen unterstützt, jedoch nicht generell?
edit : Roger Pates Kommentar im Thread std :: string in struct - Probleme beim Kopieren / Zuweisen? scheint in die allgemeine Richtung der Antwort zu zeigen, aber ich weiß nicht genug, um es selbst zu bestätigen.
edit 2 : Viele ausgezeichnete Antworten. Ich habe mich für Luther Blissett entschieden , weil ich mich hauptsächlich über die philosophischen oder historischen Gründe für das Verhalten gewundert habe , aber auch James McNellis 'Verweis auf die zugehörige Spezifikationsdokumentation war nützlich.
memcpy()
oder ähnliches.boost::array
( boost.org/doc/libs/release/doc/html/array.html ) und jetztstd::array
( en.cppreference.com/w/cpp/container/array ) sind STL-kompatible Alternativen zu chaotisch alte C-Arrays. Sie unterstützen die Zuweisung von Kopien.Antworten:
Hier ist meine Meinung dazu:
Die Entwicklung der C-Sprache bietet einige Einblicke in die Entwicklung des Array-Typs in C:
Ich werde versuchen, das Array zu skizzieren:
Die Vorläufer B und BCPL von C hatten keinen bestimmten Array-Typ, eine Deklaration wie:
würde V als (nicht typisierten) Zeiger deklarieren, der so initialisiert wird, dass er auf einen nicht verwendeten Bereich von 10 "Wörtern" Speicher zeigt. B bereits verwendet
*
für Zeiger Dereferenzierung und hatte die[]
verkürzte Schreibweise,*(V+i)
gemeintV[i]
, ebenso wie in C / C ++ heute. IstV
jedoch kein Array, ist es immer noch ein Zeiger, der auf einen Speicher zeigen muss. Dies verursachte Probleme, als Dennis Ritchie versuchte, B mit Strukturtypen zu erweitern. Er wollte, dass Arrays Teil der Strukturen sind, wie in C heute:Mit dem B, BCPL-Konzept von Arrays als Zeiger hätte das
name
Feld jedoch einen Zeiger enthalten müssen, der zur Laufzeit auf einen Speicherbereich von 14 Bytes innerhalb der Struktur initialisiert werden musste . Das Initialisierungs- / Layoutproblem wurde schließlich gelöst, indem Arrays eine Sonderbehandlung gegeben wurden: Der Compiler verfolgte die Position von Arrays in Strukturen, auf dem Stapel usw., ohne dass der Zeiger auf die Daten tatsächlich materialisiert werden musste, außer in Ausdrücken, die die Arrays betreffen. Diese Behandlung ermöglichte es, dass fast der gesamte B-Code noch ausgeführt wird, und ist die Quelle der Regel "Arrays werden in Zeiger konvertiert, wenn Sie sie betrachten" . Es ist ein Kompatibilitäts-Hack, der sich als sehr praktisch herausstellte, da er Arrays mit offener Größe usw. erlaubte.Und hier ist meine Vermutung, warum ein Array nicht zugewiesen werden kann: Da Arrays Zeiger in B waren, können Sie einfach schreiben:
ein "Array" neu zu gründen. Dies war jetzt bedeutungslos, da die Basis einer Array-Variablen kein Wert mehr war. Daher wurde diese Zuweisung nicht zugelassen, was dazu beitrug, die wenigen Programme zu erfassen, die diese Neuausrichtung auf deklarierten Arrays durchgeführt haben. Und dann blieb dieser Gedanke bestehen: Da Arrays niemals so konzipiert wurden, dass sie vom C-Typ-System erstklassig zitiert werden, wurden sie meist als spezielle Bestien behandelt, die zu Zeigern werden, wenn Sie sie verwenden. Und unter einem bestimmten Gesichtspunkt (der ignoriert, dass C-Arrays ein verpatzter Hack sind) ist es immer noch sinnvoll, die Array-Zuweisung nicht zuzulassen: Ein offenes Array oder ein Array-Funktionsparameter wird als Zeiger ohne Größeninformationen behandelt. Der Compiler verfügt nicht über die Informationen, um eine Array-Zuweisung für sie zu generieren, und die Zeigerzuweisung war aus Kompatibilitätsgründen erforderlich.
Dies änderte sich nicht, als eine Überarbeitung von C 1978 die Strukturzuweisung hinzufügte ( http://cm.bell-labs.com/cm/cs/who/dmr/cchanges.pdf ). Obwohl Aufzeichnungen waren verschiedene Typen in C, es war nicht möglich , sie in frühen K & R C. Sie zuweisen hatte sie Mitglied weise mit memcpy zu kopieren und Sie nur Zeiger auf sie als Funktionsparameter übergeben konnte. Die Zuweisung (und Parameterübergabe) wurde nun einfach als Speicher des Rohspeichers der Struktur definiert, und da dies den vorhandenen Code nicht beschädigen konnte, wurde er leicht hinzugefügt. Als unbeabsichtigter Nebeneffekt führte dies implizit zu einer Art Array-Zuweisung, die jedoch irgendwo innerhalb einer Struktur auftrat, sodass dies nicht wirklich zu Problemen bei der Verwendung von Arrays führen konnte.
quelle
int[10] c;
um den l-Wertc
als Array von zehn Elementen zu verhalten, anstatt als Zeiger auf das erste Element eines Arrays mit zehn Elementen. Es gibt einige Situationen, in denen es nützlich ist, ein typedef zu erstellen, das Speicherplatz zuweist, wenn es für eine Variable verwendet wird, aber einen Zeiger übergibt, wenn es als Funktionsargument verwendet wird. Die Unfähigkeit, einen Wert vom Typ Array zu haben, ist jedoch eine erhebliche semantische Schwäche in der Sprache.In Bezug auf die Zuweisungsoperatoren sagt der C ++ - Standard Folgendes aus (C ++ 03 §5.17 / 1):
Ein Array ist kein veränderbarer Wert.
Die Zuordnung zu einem Klassentypobjekt ist jedoch speziell definiert (§5.17 / 4):
Wir wollen also sehen, was der implizit deklarierte Kopierzuweisungsoperator für eine Klasse tut (§12.8 / 13):
Für ein Klassentypobjekt werden Arrays also korrekt kopiert. Beachten Sie, dass Sie dies nicht nutzen können, wenn Sie einen vom Benutzer deklarierten Kopierzuweisungsoperator angeben, und dass Sie das Array Element für Element kopieren müssen.
Die Argumentation ist in C ähnlich (C99 §6.5.16 / 2):
Und §6.3.2.1 / 1:
In C ist die Zuweisung viel einfacher als in C ++ (§6.5.16.1 / 2):
Für die Zuweisung von Objekten vom Typ Struktur müssen der linke und der rechte Operand denselben Typ haben, sodass der Wert des rechten Operanden einfach in den linken Operanden kopiert wird.
quelle
=
ein erfordert rvalue auf der RHS und ein Array kann nicht sein rvalue ! Die Konvertierung von lWert zu rWert ist für Arrays verboten, die durch lWert zu Zeiger ersetzt werden.static_cast
ist nicht besser darin, einen Wert zu erstellen, weil er in denselben Begriffen definiert ist.In diesem Link: http://www2.research.att.com/~bs/bs_faq2.html gibt es einen Abschnitt zur Array-Zuweisung:
Die zwei grundlegenden Probleme mit Arrays sind die folgenden
Und ich denke, das ist der grundlegende Unterschied zwischen Arrays und Strukturen. Eine Array-Variable ist ein Datenelement auf niedriger Ebene mit begrenzter Selbsterkenntnis. Grundsätzlich ist es ein Stück Speicher und eine Möglichkeit, sich darin zu indizieren.
Der Compiler kann also den Unterschied zwischen int a [10] und int b [20] nicht erkennen.
Strukturen haben jedoch nicht die gleiche Mehrdeutigkeit.
quelle
sizeof(a)
Vergleich zusizeof(b)
oder Übergebena
anvoid f(int (&)[20]);
.Ich weiß, jeder, der geantwortet hat, ist Experte für C / C ++. Aber ich dachte, das ist der Hauptgrund.
num2 = num1;
Hier versuchen Sie, die Basisadresse des Arrays zu ändern, was nicht zulässig ist.
und natürlich struct2 = struct1;
Hier wird das Objekt struct1 einem anderen Objekt zugewiesen.
quelle
num2 = num1
wären , würden sie sich perfekt verhalten. Die Elemente vonnum2
hätten den gleichen Wert wie das entsprechende Element vonnum1
.Ein weiterer Grund , keine weiteren Anstrengungen unternommen wurden Arrays in C , zu Rindfleisch ist wahrscheinlich , dass Array Zuweisung wäre nicht , dass nützlich. Obwohl dies in C leicht erreicht werden kann, indem es in eine Struktur eingeschlossen wird (und die Adresse der Struktur einfach zur weiteren Verarbeitung in die Adresse des Arrays oder sogar in die Adresse des ersten Elements des Arrays umgewandelt werden kann), wird diese Funktion selten verwendet. Ein Grund dafür ist, dass Arrays unterschiedlicher Größe nicht kompatibel sind, was die Vorteile der Zuweisung oder der damit verbundenen Übergabe an Funktionen nach Wert einschränkt.
Die meisten Funktionen mit Array-Parametern in Sprachen, in denen Arrays erstklassige Typen sind, werden für Arrays beliebiger Größe geschrieben. Die Funktion iteriert dann normalerweise über die angegebene Anzahl von Elementen, eine Information, die das Array bereitstellt. (In C besteht die Redewendung natürlich darin, einen Zeiger und eine separate Elementanzahl zu übergeben.) Eine Funktion, die ein Array mit nur einer bestimmten Größe akzeptiert, wird nicht so oft benötigt, sodass nicht viel übersehen wird. (Dies ändert sich, wenn Sie es dem Compiler überlassen können, eine separate Funktion für jede auftretende Arraygröße zu generieren, wie bei C ++ - Vorlagen. Dies ist der Grund, warum dies
std::array
nützlich ist.)quelle