Der folgende Code wird nicht kompiliert.
int a = 1, b = 2, c = 3;
int& arr[] = {a,b,c,8};
Was sagt der C ++ - Standard dazu?
Ich weiß, ich könnte eine Klasse deklarieren, die eine Referenz enthält, und dann ein Array dieser Klasse erstellen, wie unten gezeigt. Aber ich möchte wirklich wissen, warum der obige Code nicht kompiliert wird.
struct cintref
{
cintref(const int & ref) : ref(ref) {}
operator const int &() { return ref; }
private:
const int & ref;
void operator=(const cintref &);
};
int main()
{
int a=1,b=2,c=3;
//typedef const int & cintref;
cintref arr[] = {a,b,c,8};
}
Es ist möglich, ein Array von Referenzen zu simulieren, struct cintref
anstatt es const int &
zu simulieren.
intlink value = 8;
funktioniert. Überprüfen Sie, ob Sie nicht glauben.operator=
. Referenzen können nicht erneut eingesetzt werden. Wenn Sie wirklich eine solche Semantik wollen - obwohl ich persönlich nicht eine Situation gefunden , in dem sie praktisch nützlich sind - dannstd::reference_wrapper
wäre der Weg , es zu tun, wie es tatsächlich einen Zeiger speichert , sondern bietet Referenz wieoperator
s und ist erneutes Einsetzen ermöglichen. Aber dann würde ich einfach einen Zeiger benutzen!Antworten:
Bei der Beantwortung Ihrer Frage zum Standard kann ich den C ++ - Standard §8.3.2 / 4 zitieren :
quelle
struct
deren einziges Mitglied eine Referenz ist. Auf diese Weise haben Sie jetzt sowohl eine Referenz als auch ein übergeordnetes Objekt zu benennen. Dies bedeutet, dass Sie jetzt eindeutig angeben können, welche Adresse Sie möchten. Scheint offensichtlich ... also warum hat es niemand gesagt?What more is there to say?
Eine Begründung für warum ? Ich beschäftige mich ausschließlich mit dem Standard, aber nur das Zitieren und die Annahme, dass dies das Ende der Diskussion ist, scheint ein sicherer Weg zu sein, um das kritische Denken der Benutzer zu zerstören - zusammen mit jeglichem Potenzial für die Entwicklung der Sprache, z. B. über die Grenzen der Auslassung hinaus oder künstliche Einschränkung. Es gibt zu viel, weil der Standard "hier - und nicht genug" sagt, und es ist aus den folgenden praktischen Gründen sehr sinnvoll, das zu sagen. Ich weiß nicht, warum Upvotes so eifrig zu Antworten fließen, die nur die ersteren sagen, ohne auch nur zu versuchen, die letzteren zu erforschen.Referenzen sind keine Objekte. Sie haben keinen eigenen Speicher, sie verweisen nur auf vorhandene Objekte. Aus diesem Grund ist es nicht sinnvoll, Referenzarrays zu haben.
Wenn Sie ein leichtes Objekt möchten, das auf ein anderes Objekt verweist, können Sie einen Zeiger verwenden. Sie können ein
struct
mit einem Referenzelement nur als Objekte in Arrays verwenden, wenn Sie für alle Referenzelemente für allestruct
Instanzen eine explizite Initialisierung bereitstellen . Referenzen können nicht standardmäßig initialisiert werden.Bearbeiten: Wie jia3ep bemerkt, gibt es im Standardabschnitt zu Deklarationen ein explizites Verbot von Arrays von Referenzen.
quelle
Dies ist eine interessante Diskussion. Es ist klar, dass Arrays von Refs absolut illegal sind, aber meiner Meinung nach ist der Grund dafür nicht so einfach zu sagen: "Sie sind keine Objekte" oder "Sie haben keine Größe". Ich möchte darauf hinweisen, dass Arrays selbst in C / C ++ keine vollwertigen Objekte sind. Wenn Sie dem widersprechen, versuchen Sie, einige STL-Vorlagenklassen mithilfe eines Arrays als Vorlagenparameter 'class' zu instanziieren, und sehen Sie, was passiert. Sie können sie nicht zurückgeben, zuweisen oder als Parameter übergeben. (Ein Array-Parameter wird als Zeiger behandelt). Es ist jedoch legal, Arrays von Arrays zu erstellen. Referenzen haben eine Größe, die der Compiler berechnen kann und muss - Sie können eine Referenz nicht sizeof (), aber Sie können eine Struktur erstellen, die nur Referenzen enthält. Die Größe reicht aus, um alle Zeiger zu enthalten, die die Referenzen implementieren. Sie können'
Tatsächlich können Sie diese Zeile zur Strukturdefinition hinzufügen
... und jetzt habe ich etwas, das VIEL wie eine Reihe von Refs aussieht:
Dies ist kein echtes Array, sondern eine Operatorüberladung. Es werden keine Dinge ausgeführt, die Arrays normalerweise tun, wie z. B. sizeof (arr) / sizeof (arr [0]). Aber es macht genau das, was ich von einer Reihe von Referenzen möchte, mit vollkommen legalem C ++. Außer (a) es ist mühsam, mehr als 3 oder 4 Elemente einzurichten, und (b) es führt eine Berechnung mit einer Reihe von ?: Dies kann mithilfe der Indizierung erfolgen (nicht mit der normalen C-Zeiger-Berechnungssemantik-Indizierung) , aber trotzdem indizieren). Ich würde gerne einen sehr begrenzten 'Array of Reference'-Typ sehen, der dies tatsächlich kann. Das heißt, ein Array von Referenzen würde nicht als allgemeines Array von Dingen behandelt, die Referenzen sind, sondern es wäre ein neues 'Array von Referenzen'. mit Vorlagen machen).
Dies würde wahrscheinlich funktionieren, wenn Ihnen diese Art von Bösartigkeit nichts ausmacht: Neufassung von '* this' als Array von int * 's und Rückgabe einer Referenz aus einem: (nicht empfohlen, aber es zeigt, wie das richtige' Array ' würde funktionieren):
quelle
std::tuple<int&,int&,int&> abcref = std::tie( a,b,c)
- wodurch ein "Array" von Referenzen erstellt wird, die nur durch Konstanten zur Kompilierungszeit mit std :: get indiziert werden können. Aber du kannst es nicht tunstd::array<int&,3> abcrefarr = std::tie( a,b,c)
. Vielleicht gibt es einen Weg, den ich nicht kenne. Es scheint mir, dass es eine Möglichkeit geben sollte, eine Spezialisierung zu schreiben,std::array<T&,N>
die dies kann - und damit eine Funktion,std::tiearray(...)
die eine solche zurückgibt (oder es erlaubtstd::array<T&,N>
, Initialisierer zu akzeptieren, die Adressen = {& v1, & v2 usw.} enthalten)?:
std::array<T,N>
, im App-Code leicht zu definierende Element wurde erst in c ++ 11 zu std :: hinzugefügt, vermutlich weil es schwierig ist, dies ohne Möglichkeit zu haben do= {1,2,3};
war , dass ‚Sprache Hacking‘?Kommentar zu Ihrer Bearbeitung:
Bessere Lösung ist
std::reference_wrapper
.Details: http://www.cplusplus.com/reference/functional/reference_wrapper/
Beispiel:
quelle
reference_wrapper
.Ein Array kann implizit in einen Zeiger konvertiert werden, und der Verweis auf eine Referenz ist in C ++ unzulässig
quelle
Gegeben
int& arr[] = {a,b,c,8};
, was istsizeof(*arr)
?Überall sonst wird eine Referenz einfach als das Ding selbst behandelt,
sizeof(*arr)
sollte es also einfach seinsizeof(int)
. Dies würde jedoch dazu führen, dass die Array-Zeiger-Arithmetik für dieses Array falsch ist (vorausgesetzt, dass Referenzen nicht die gleiche Breite haben, ist ints). Um die Mehrdeutigkeit zu beseitigen, ist es verboten.quelle
struct
deren einziges Mitglied diese Referenz ist und finden Sie es heraus ..?Denn wie viele hier gesagt haben, sind Referenzen keine Objekte. Sie sind einfach Aliase. Einige Compiler implementieren sie möglicherweise als Zeiger, aber der Standard erzwingt / spezifiziert dies nicht. Und da Referenzen keine Objekte sind, können Sie nicht darauf verweisen. Das Speichern von Elementen in einem Array bedeutet, dass es eine Art Indexadresse gibt (dh auf Elemente an einem bestimmten Index zeigen). und deshalb können Sie keine Arrays von Referenzen haben, weil Sie nicht auf sie verweisen können.
Verwenden Sie stattdessen boost :: reference_wrapper oder boost :: tuple. oder nur Zeiger.
quelle
Ich glaube, die Antwort ist sehr einfach und hat mit semantischen Referenzregeln und dem Umgang mit Arrays in C ++ zu tun.
Kurz gesagt: Referenzen können als Strukturen betrachtet werden, die keinen Standardkonstruktor haben, daher gelten dieselben Regeln.
1) Referenzen haben semantisch keinen Standardwert. Referenzen können nur durch Referenzieren erstellt werden. Referenzen haben keinen Wert, der das Fehlen einer Referenz darstellt.
2) Beim Zuweisen eines Arrays der Größe X erstellt das Programm eine Sammlung von standardmäßig initialisierten Objekten. Da die Referenz keinen Standardwert hat, ist das Erstellen eines solchen Arrays semantisch unzulässig.
Diese Regel gilt auch für Strukturen / Klassen, die keinen Standardkonstruktor haben. Das folgende Codebeispiel wird nicht kompiliert:
quelle
Object
, Sie müssen nur sicherstellen, dass Sie alle initialisieren :Object objects[1] = {Object(42)};
. In der Zwischenzeit können Sie kein Array von Referenzen erstellen, selbst wenn Sie alle initialisieren.Mit dieser Vorlagenstruktur können Sie ziemlich nahe kommen. Sie müssen jedoch mit Ausdrücken initialisieren, die Zeiger auf T und nicht auf T sind. Obwohl Sie auf einfache Weise ein 'fake_constref_array' erstellen können, können Sie dies nicht wie im Beispiel des OP ('8') an rvalues binden.
-> A = 0 B = 7 X = {0,8,0}
quelle
Ein Referenzobjekt hat keine Größe. Wenn Sie schreiben
sizeof(referenceVariable)
, erhalten Sie die Größe des Objekts, auf das verwiesen wirdreferenceVariable
, nicht die der Referenz selbst. Es hat keine eigene Größe, weshalb der Compiler nicht berechnen kann, wie viel Größe das Array benötigen würde.quelle
Wenn Sie etwas in einem Array speichern, muss dessen Größe bekannt sein (da die Array-Indizierung von der Größe abhängt). Gemäß dem C ++ - Standard ist nicht angegeben, ob eine Referenz gespeichert werden muss oder nicht, sodass eine Indizierung eines Array von Referenzen nicht möglich wäre.
quelle
struct
, wird auf magische Weise alles spezifiziert, genau definiert, garantiert und von deterministischer Größe. Warum besteht also dieser scheinbar völlig künstliche Unterschied?struct
verleiht, beginnen sich einige gute mögliche Antworten zu ergeben - aber für mich hat dies noch niemand getan, obwohl dies eine der unmittelbaren Herausforderungen für alle Gemeinsamen ist Gründe, warum Sie keine unverpackten Refs verwenden können.Nur um das ganze Gespräch zu ergänzen. Da für Arrays aufeinanderfolgende Speicherorte zum Speichern des Elements erforderlich sind, kann beim Erstellen eines Arrays von Referenzen nicht garantiert werden, dass sie sich an aufeinanderfolgenden Speicherorten befinden, sodass der Zugriff ein Problem darstellt und wir daher nicht einmal alle mathematischen Operationen anwenden können Array.
quelle
Betrachten Sie ein Array von Zeigern. Ein Zeiger ist wirklich eine Adresse; Wenn Sie also das Array initialisieren, sagen Sie dem Computer analog: "Weisen Sie diesen Speicherblock zu, um diese X-Nummern (die Adressen anderer Elemente sind) zu speichern." Wenn Sie dann einen der Zeiger ändern, ändern Sie nur das, worauf er zeigt. es ist immer noch eine numerische Adresse, die selbst an derselben Stelle sitzt.
Eine Referenz ist analog zu einem Alias. Wenn Sie eine Reihe von Referenzen deklarieren würden, würden Sie dem Computer im Grunde sagen: "Ordnen Sie diesen amorphen Speicherklumpen zu, der aus all diesen verschiedenen verstreuten Elementen besteht."
quelle
struct
Mitglieds, dessen einziges Mitglied eine Referenz ist, zu etwas völlig Legalem, Vorhersehbarem und Nicht-Amorphem? Warum muss ein Benutzer eine Referenz einschließen, damit er auf magische Weise Array-fähige Kräfte erhält, oder handelt es sich nur um eine künstliche Einschränkung? IMO keine Antwort hat dies direkt angesprochen. Ich gehe davon aus, dass die Widerlegung lautet: "Das Wrapping-Objekt stellt sicher, dass Sie die Wertesemantik in Form des Wrapping-Objekts verwenden können, sodass Sie die Garantien für Werte haben, die erforderlich sind, weil z. B. wie man zwischen Element- und Schiedsrichteradresse unterscheiden würde." ... Ist es das, was du meintest?Eigentlich ist dies eine Mischung aus C- und C ++ - Syntax.
Sie sollten entweder reine C-Arrays verwenden, die keine Referenzen enthalten können, da Referenzen nur Teil von C ++ sind. Oder Sie gehen den C ++ - Weg und verwenden das
std::vector
oderstd::array
Klasse für Ihren Zweck.Was den bearbeiteten Teil betrifft: Obwohl das
struct
ein Element aus C ist, definieren Sie einen Konstruktor und Operatorfunktionen, die es zu einem C ++ machenclass
. Folglichstruct
würden Sie nicht in reinem C kompilieren!quelle
std::vector
oderstd::array
kann auch keine Referenzen enthalten. Der C ++ Standard ist ziemlich explizit, dass kein Container kann.